mirror of
https://github.com/github/codeql.git
synced 2026-05-25 00:27:09 +02:00
Merge tag 'codeql-cli/latest'
Compatible with the latest released version of the CodeQL CLI
This commit is contained in:
@@ -3,3 +3,5 @@
|
||||
*/venv/
|
||||
**/*.egg-info/
|
||||
*/.cache
|
||||
**/trap/
|
||||
**/*.testproj/
|
||||
@@ -13,10 +13,10 @@ rm -rf dbs
|
||||
|
||||
mkdir dbs
|
||||
|
||||
CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB=True $CODEQL database create dbs/without-stdlib --language python --source-root repo_dir/
|
||||
$CODEQL database create dbs/without-stdlib --language python --source-root repo_dir/
|
||||
$CODEQL query run --database dbs/without-stdlib query.ql > query.without-stdlib.actual
|
||||
diff query.without-stdlib.expected query.without-stdlib.actual
|
||||
|
||||
LGTM_INDEX_EXCLUDE="/usr/lib/**" $CODEQL database create dbs/with-stdlib --language python --source-root repo_dir/
|
||||
LGTM_INDEX_EXCLUDE="/usr/lib/**" CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB=True $CODEQL database create dbs/with-stdlib --language python --source-root repo_dir/
|
||||
$CODEQL query run --database dbs/with-stdlib query.ql > query.with-stdlib.actual
|
||||
diff query.with-stdlib.expected query.with-stdlib.actual
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
| name |
|
||||
+----------+
|
||||
| dircache |
|
||||
| stat |
|
||||
| test |
|
||||
@@ -1,5 +1,3 @@
|
||||
| name |
|
||||
+----------+
|
||||
| dircache |
|
||||
| stat |
|
||||
| test |
|
||||
| name |
|
||||
+------+
|
||||
| test |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
| name |
|
||||
+------+
|
||||
| stat |
|
||||
| test |
|
||||
|
||||
@@ -102,8 +102,10 @@ def make_parser():
|
||||
config_options.add_option("--colorize", dest="colorize", default=False, action="store_true",
|
||||
help = """Colorize the logging output.""")
|
||||
|
||||
config_options.add_option("--dont-extract-stdlib", dest="extract_stdlib", default=True, action="store_false",
|
||||
help="Do not extract the standard library.")
|
||||
config_options.add_option("--dont-extract-stdlib", dest="extract_stdlib", action="store_false",
|
||||
help="This flag is deprecated; not extracting the standard library is now the default.")
|
||||
config_options.add_option("--extract-stdlib", dest="extract_stdlib", default=False, action="store_true",
|
||||
help="Extract the standard library.")
|
||||
|
||||
parser.add_option_group(config_options)
|
||||
|
||||
@@ -226,8 +228,18 @@ def parse(command_line):
|
||||
|
||||
if 'CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB' in os.environ:
|
||||
options.extract_stdlib = False
|
||||
print ("WARNING: CODEQL_EXTRACTOR_PYTHON_DONT_EXTRACT_STDLIB is deprecated; the default is now to not extract the standard library.")
|
||||
|
||||
if 'CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB' in os.environ:
|
||||
options.extract_stdlib = True
|
||||
|
||||
options.prune = True
|
||||
|
||||
if options.extract_stdlib:
|
||||
print ("WARNING: The analysis will extract the standard library. This behavior is deprecated and will be removed in a future release. We expect it to be gone in CLI version 2.20.0.")
|
||||
else:
|
||||
print ("INFO: The Python extractor has recently stopped extracting the standard library by default. If you encounter problems, please let us know by submitting an issue to https://github.com/github/codeql. It is possible to re-enable extraction of the standard library by setting the environment variable CODEQL_EXTRACTOR_PYTHON_EXTRACT_STDLIB.")
|
||||
|
||||
return options, args
|
||||
|
||||
def split_and_flatten(options_list, div):
|
||||
|
||||
@@ -67,7 +67,7 @@ def main(sys_path = sys.path[:]):
|
||||
update_analysis_version(last_version)
|
||||
|
||||
found_py2 = False
|
||||
if get_analysis_major_version() == 2:
|
||||
if get_analysis_major_version() == 2 and options.extract_stdlib:
|
||||
# Setup `sys_path` to use the Python 2 standard library
|
||||
sys_path, found_py2 = get_py2_sys_path(logger, sys_path)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from io import BytesIO
|
||||
|
||||
#Semantic version of extractor.
|
||||
#Update this if any changes are made
|
||||
VERSION = "6.1.2"
|
||||
VERSION = "7.0.0"
|
||||
|
||||
PY_EXTENSIONS = ".py", ".pyw"
|
||||
|
||||
|
||||
2
python/extractor/tests/parser/.gitignore
vendored
Normal file
2
python/extractor/tests/parser/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.old
|
||||
*.new
|
||||
@@ -1,3 +1,13 @@
|
||||
## 2.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Modelled that `re.finditer` returns an iterable of `re.Match` objects. This is now understood by the API graph in many cases.
|
||||
* Type tracking, and hence the API graph, is now able to correctly trace through comprehensions.
|
||||
* More precise modelling of the dataflow through comprehensions. In particular, captured variables are now handled correctly.
|
||||
* Dataflow out of yield is added, allowing proper tracing through generators.
|
||||
* Added several models of standard library functions and classes, in anticipation of no longer extracting the standard library in a future release.
|
||||
|
||||
## 2.1.0
|
||||
|
||||
### New Features
|
||||
|
||||
9
python/ql/lib/change-notes/released/2.1.1.md
Normal file
9
python/ql/lib/change-notes/released/2.1.1.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 2.1.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Modelled that `re.finditer` returns an iterable of `re.Match` objects. This is now understood by the API graph in many cases.
|
||||
* Type tracking, and hence the API graph, is now able to correctly trace through comprehensions.
|
||||
* More precise modelling of the dataflow through comprehensions. In particular, captured variables are now handled correctly.
|
||||
* Dataflow out of yield is added, allowing proper tracing through generators.
|
||||
* Added several models of standard library functions and classes, in anticipation of no longer extracting the standard library in a future release.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.1.0
|
||||
lastReleaseVersion: 2.1.1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-all
|
||||
version: 2.1.0
|
||||
version: 2.1.1
|
||||
groups: python
|
||||
dbscheme: semmlecode.python.dbscheme
|
||||
extractor: python
|
||||
|
||||
@@ -843,6 +843,13 @@ module API {
|
||||
ref = pred.getSubscript(_) and
|
||||
ref.asCfgNode().isLoad()
|
||||
or
|
||||
// Subscript via comprehension
|
||||
lbl = Label::subscript() and
|
||||
exists(PY::Comp comp |
|
||||
pred.asExpr() = comp.getIterable() and
|
||||
ref.asExpr() = comp.getNthInnerLoop(0).getTarget()
|
||||
)
|
||||
or
|
||||
// Subclassing a node
|
||||
lbl = Label::subclass() and
|
||||
exists(PY::ClassExpr clsExpr, DataFlow::Node superclass | pred.flowsTo(superclass) |
|
||||
|
||||
@@ -163,6 +163,10 @@ newtype TArgumentPosition =
|
||||
// position, we need to ensure we make these available (these are specified as
|
||||
// parameters in the flow-summary spec)
|
||||
FlowSummaryImpl::ParsePositions::isParsedPositionalParameterPosition(_, index)
|
||||
or
|
||||
// the generated function inside a comprehension has a positional argument at index 0
|
||||
exists(Comp c) and
|
||||
index = 0
|
||||
} or
|
||||
TKeywordArgumentPosition(string name) {
|
||||
exists(any(CallNode c).getArgByName(name))
|
||||
@@ -314,12 +318,11 @@ newtype TDataFlowCallable =
|
||||
* class instantiations, and (in the future) special methods.
|
||||
*/
|
||||
TFunction(Function func) {
|
||||
// For generators/list-comprehensions we create a synthetic function. In the
|
||||
// points-to call-graph these were not considered callable, and instead we added
|
||||
// data-flow steps (read/write) for these. As an easy solution for now, we do the
|
||||
// same to keep things easy to reason about (and therefore exclude things that do
|
||||
// not have a definition)
|
||||
// Functions with an explicit definition
|
||||
exists(func.getDefinition())
|
||||
or
|
||||
// For generators/list-comprehensions we create a synthetic function.
|
||||
exists(Comp c | c.getFunction() = func)
|
||||
} or
|
||||
/** see QLDoc for `DataFlowModuleScope` for why we need this. */
|
||||
TModule(Module m) or
|
||||
@@ -378,14 +381,13 @@ abstract class DataFlowFunction extends DataFlowCallable, TFunction {
|
||||
int positionalOffset() { result = 0 }
|
||||
|
||||
override ParameterNode getParameter(ParameterPosition ppos) {
|
||||
// Do not handle lower bound positions (such as `[1..]`) here
|
||||
// they are handled by parameter matching and would create
|
||||
// inconsistencies here as multiple parameters could match such a position.
|
||||
exists(int index | ppos.isPositional(index) |
|
||||
result.getParameter() = func.getArg(index + this.positionalOffset())
|
||||
)
|
||||
or
|
||||
exists(int index1, int index2 | ppos.isPositionalLowerBound(index1) and index2 >= index1 |
|
||||
result.getParameter() = func.getArg(index2 + this.positionalOffset())
|
||||
)
|
||||
or
|
||||
exists(string name | ppos.isKeyword(name) | result.getParameter() = func.getArgByName(name))
|
||||
or
|
||||
// `*args`
|
||||
@@ -1392,6 +1394,8 @@ private predicate sameEnclosingCallable(Node node1, Node node2) {
|
||||
// =============================================================================
|
||||
newtype TDataFlowCall =
|
||||
TNormalCall(CallNode call, Function target, CallType type) { resolveCall(call, target, type) } or
|
||||
/** A call to the generated function inside a comprehension */
|
||||
TComprehensionCall(Comp c) or
|
||||
TPotentialLibraryCall(CallNode call) or
|
||||
/** A synthesized call inside a summarized callable */
|
||||
TSummaryCall(
|
||||
@@ -1495,6 +1499,34 @@ class NormalCall extends ExtractedDataFlowCall, TNormalCall {
|
||||
CallType getCallType() { result = type }
|
||||
}
|
||||
|
||||
/** A call to the generated function inside a comprhension */
|
||||
class ComprehensionCall extends ExtractedDataFlowCall, TComprehensionCall {
|
||||
Comp c;
|
||||
Function target;
|
||||
|
||||
ComprehensionCall() {
|
||||
this = TComprehensionCall(c) and
|
||||
target = c.getFunction()
|
||||
}
|
||||
|
||||
Comp getComprehension() { result = c }
|
||||
|
||||
override string toString() { result = "comprehension call" }
|
||||
|
||||
override ControlFlowNode getNode() { result.getNode() = c }
|
||||
|
||||
override Scope getScope() { result = c.getScope() }
|
||||
|
||||
override DataFlowCallable getCallable() { result.(DataFlowFunction).getScope() = target }
|
||||
|
||||
override ArgumentNode getArgument(ArgumentPosition apos) {
|
||||
result.asExpr() = c.getIterable() and
|
||||
apos.isPositional(0)
|
||||
}
|
||||
|
||||
override Location getLocation() { result = c.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A potential call to a summarized callable, a `LibraryCallable`.
|
||||
*
|
||||
@@ -1725,6 +1757,47 @@ class CapturedVariablesArgumentNode extends CfgNode, ArgumentNode {
|
||||
}
|
||||
}
|
||||
|
||||
/** A synthetic node representing the values of variables captured by a comprehension. */
|
||||
class SynthCompCapturedVariablesArgumentNode extends Node, TSynthCompCapturedVariablesArgumentNode,
|
||||
ArgumentNode
|
||||
{
|
||||
Comp comp;
|
||||
|
||||
SynthCompCapturedVariablesArgumentNode() { this = TSynthCompCapturedVariablesArgumentNode(comp) }
|
||||
|
||||
override string toString() { result = "Capturing closure argument (comp)" }
|
||||
|
||||
override Scope getScope() { result = comp.getScope() }
|
||||
|
||||
override Location getLocation() { result = comp.getLocation() }
|
||||
|
||||
Comp getComprehension() { result = comp }
|
||||
|
||||
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
call.(ComprehensionCall).getComprehension() = comp and
|
||||
pos.isLambdaSelf()
|
||||
}
|
||||
}
|
||||
|
||||
/** A synthetic node representing the values of variables captured by a comprehension after the output has been computed. */
|
||||
class SynthCompCapturedVariablesArgumentPostUpdateNode extends PostUpdateNodeImpl,
|
||||
TSynthCompCapturedVariablesArgumentPostUpdateNode
|
||||
{
|
||||
Comp comp;
|
||||
|
||||
SynthCompCapturedVariablesArgumentPostUpdateNode() {
|
||||
this = TSynthCompCapturedVariablesArgumentPostUpdateNode(comp)
|
||||
}
|
||||
|
||||
override string toString() { result = "[post] Capturing closure argument (comp)" }
|
||||
|
||||
override Scope getScope() { result = comp.getScope() }
|
||||
|
||||
override Location getLocation() { result = comp.getLocation() }
|
||||
|
||||
override Node getPreUpdateNode() { result = TSynthCompCapturedVariablesArgumentNode(comp) }
|
||||
}
|
||||
|
||||
/** Gets a viable run-time target for the call `call`. */
|
||||
DataFlowCallable viableCallable(DataFlowCall call) {
|
||||
call instanceof ExtractedDataFlowCall and
|
||||
@@ -1764,7 +1837,10 @@ abstract class ReturnNode extends Node {
|
||||
/** A data flow node that represents a value returned by a callable. */
|
||||
class ExtractedReturnNode extends ReturnNode, CfgNode {
|
||||
// See `TaintTrackingImplementation::returnFlowStep`
|
||||
ExtractedReturnNode() { node = any(Return ret).getValue().getAFlowNode() }
|
||||
ExtractedReturnNode() {
|
||||
node = any(Return ret).getValue().getAFlowNode() or
|
||||
node = any(Yield yield).getAFlowNode()
|
||||
}
|
||||
|
||||
override ReturnKind getKind() { any() }
|
||||
}
|
||||
|
||||
@@ -168,6 +168,26 @@ private predicate synthDictSplatArgumentNodeStoreStep(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` is the value yielded by the `yield` found at `nodeTo`.
|
||||
*
|
||||
* For example, in
|
||||
* ```python
|
||||
* for x in l:
|
||||
* yield x.name
|
||||
* ```
|
||||
* data from `x.name` is stored into the `yield` (and can subsequently be read out of the iterable).
|
||||
*/
|
||||
predicate yieldStoreStep(Node nodeFrom, Content c, Node nodeTo) {
|
||||
exists(Yield yield |
|
||||
nodeTo.asCfgNode() = yield.getAFlowNode() and
|
||||
nodeFrom.asCfgNode() = yield.getValue().getAFlowNode() and
|
||||
// TODO: Consider if this will also need to transfer dictionary content
|
||||
// once dictionary comprehensions are supported.
|
||||
c instanceof ListElementContent
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the a `**kwargs` parameter will not contain elements with names of
|
||||
* keyword parameters.
|
||||
@@ -256,6 +276,12 @@ abstract class PostUpdateNodeImpl extends Node {
|
||||
abstract Node getPreUpdateNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* A post-update node synthesised for an existing control flow node.
|
||||
* Add to `TSyntheticPostUpdateNode` to get the synthetic post-update node synthesised.
|
||||
*
|
||||
* Synthetic post-update nodes for synthetic nodes need to be listed one by one.
|
||||
*/
|
||||
class SyntheticPostUpdateNode extends PostUpdateNodeImpl, TSyntheticPostUpdateNode {
|
||||
ControlFlowNode node;
|
||||
|
||||
@@ -270,6 +296,11 @@ class SyntheticPostUpdateNode extends PostUpdateNodeImpl, TSyntheticPostUpdateNo
|
||||
override Location getLocation() { result = node.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An existsing control flow node being the post-update node of a synthetic pre-update node.
|
||||
*
|
||||
* Synthetic post-update nodes for synthetic nodes need to be listed one by one.
|
||||
*/
|
||||
class NonSyntheticPostUpdateNode extends PostUpdateNodeImpl, CfgNode {
|
||||
SyntheticPreUpdateNode pre;
|
||||
|
||||
@@ -668,8 +699,6 @@ predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
|
||||
or
|
||||
setStoreStep(nodeFrom, c, nodeTo)
|
||||
or
|
||||
comprehensionStoreStep(nodeFrom, c, nodeTo)
|
||||
or
|
||||
attributeStoreStep(nodeFrom, c, nodeTo)
|
||||
or
|
||||
matchStoreStep(nodeFrom, c, nodeTo)
|
||||
@@ -683,6 +712,8 @@ predicate storeStep(Node nodeFrom, ContentSet c, Node nodeTo) {
|
||||
or
|
||||
synthDictSplatArgumentNodeStoreStep(nodeFrom, c, nodeTo)
|
||||
or
|
||||
yieldStoreStep(nodeFrom, c, nodeTo)
|
||||
or
|
||||
VariableCapture::storeStep(nodeFrom, c, nodeTo)
|
||||
}
|
||||
|
||||
@@ -843,31 +874,6 @@ predicate dictClearStep(Node node, DictionaryElementContent c) {
|
||||
)
|
||||
}
|
||||
|
||||
/** Data flows from an element expression in a comprehension to the comprehension. */
|
||||
predicate comprehensionStoreStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
|
||||
// Comprehension
|
||||
// `[x+1 for x in l]`
|
||||
// nodeFrom is `x+1`, cfg node
|
||||
// nodeTo is `[x+1 for x in l]`, cfg node
|
||||
// c denotes list or set or dictionary without index
|
||||
//
|
||||
// List
|
||||
nodeTo.getNode().getNode().(ListComp).getElt() = nodeFrom.getNode().getNode() and
|
||||
c instanceof ListElementContent
|
||||
or
|
||||
// Set
|
||||
nodeTo.getNode().getNode().(SetComp).getElt() = nodeFrom.getNode().getNode() and
|
||||
c instanceof SetElementContent
|
||||
or
|
||||
// Dictionary
|
||||
nodeTo.getNode().getNode().(DictComp).getElt() = nodeFrom.getNode().getNode() and
|
||||
c instanceof DictionaryElementAnyContent
|
||||
or
|
||||
// Generator
|
||||
nodeTo.getNode().getNode().(GeneratorExp).getElt() = nodeFrom.getNode().getNode() and
|
||||
c instanceof ListElementContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` flows into the attribute `c` of `nodeTo` via an attribute assignment.
|
||||
*
|
||||
|
||||
@@ -71,6 +71,9 @@ newtype TNode =
|
||||
def.getDefiningNode() = node and
|
||||
def.getParameter() = func.getArg(0)
|
||||
)
|
||||
or
|
||||
// the iterable argument to the implicit comprehension function
|
||||
node.getNode() = any(Comp c).getIterable()
|
||||
} or
|
||||
/** A node representing a global (module-level) variable in a specific module. */
|
||||
TModuleVariableNode(Module m, GlobalVariable v) {
|
||||
@@ -124,9 +127,16 @@ newtype TNode =
|
||||
/** A synthetic node representing the heap of a function. Used for variable capture. */
|
||||
TSynthCapturedVariablesParameterNode(Function f) {
|
||||
f = any(VariableCapture::CapturedVariable v).getACapturingScope() and
|
||||
// TODO: Remove this restriction when adding proper support for captured variables in the body of the function we generate for comprehensions
|
||||
exists(TFunction(f))
|
||||
} or
|
||||
/** A synthetic node representing the values of variables captured by a comprehension. */
|
||||
TSynthCompCapturedVariablesArgumentNode(Comp comp) {
|
||||
comp.getFunction() = any(VariableCapture::CapturedVariable v).getACapturingScope()
|
||||
} or
|
||||
/** A synthetic node representing the values of variables captured by a comprehension after the output has been computed. */
|
||||
TSynthCompCapturedVariablesArgumentPostUpdateNode(Comp comp) {
|
||||
comp.getFunction() = any(VariableCapture::CapturedVariable v).getACapturingScope()
|
||||
} or
|
||||
/** An empty, unused node type that exists to prevent unwanted dependencies on data flow nodes. */
|
||||
TForbiddenRecursionGuard() {
|
||||
none() and
|
||||
@@ -350,6 +360,9 @@ class ExtractedArgumentNode extends ArgumentNode {
|
||||
or
|
||||
// and self arguments
|
||||
this.asCfgNode() = any(CallNode c).getFunction().(AttrNode).getObject()
|
||||
or
|
||||
// for comprehensions, we allow the synthetic `iterable` argument
|
||||
this.asExpr() = any(Comp c).getIterable()
|
||||
}
|
||||
|
||||
final override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
|
||||
|
||||
@@ -187,7 +187,7 @@ class ForTarget extends ControlFlowNode {
|
||||
)
|
||||
or
|
||||
exists(Comp comp |
|
||||
source = comp.getIterable() and
|
||||
source = comp.getFunction().getArg(0) and
|
||||
this.getNode() = comp.getNthInnerLoop(0).getTarget()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -46,8 +46,6 @@ private module Cached {
|
||||
or
|
||||
containerStep(nodeFrom, nodeTo)
|
||||
or
|
||||
copyStep(nodeFrom, nodeTo)
|
||||
or
|
||||
DataFlowPrivate::forReadStep(nodeFrom, _, nodeTo)
|
||||
or
|
||||
DataFlowPrivate::iterableUnpackingReadStep(nodeFrom, _, nodeTo)
|
||||
@@ -188,19 +186,7 @@ predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
// TODO: once we have proper flow-summary modeling, we might not need this step any
|
||||
// longer -- but there needs to be a matching read-step for the store-step, and we
|
||||
// don't provide that right now.
|
||||
DataFlowPrivate::comprehensionStoreStep(nodeFrom, _, nodeTo)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if taint can flow from `nodeFrom` to `nodeTo` with a step related to copying.
|
||||
*/
|
||||
predicate copyStep(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeTo) {
|
||||
exists(DataFlow::CallCfgNode call | call = nodeTo |
|
||||
call = API::moduleImport("copy").getMember(["copy", "deepcopy"]).getACall() and
|
||||
call.getArg(0) = nodeFrom
|
||||
)
|
||||
or
|
||||
nodeTo.(DataFlow::MethodCallNode).calls(nodeFrom, "copy")
|
||||
DataFlowPrivate::yieldStoreStep(nodeFrom, _, nodeTo)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -304,7 +304,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
|
||||
var.hasDefiningNode(def)
|
||||
|
|
||||
nodeTo.(DataFlowPublic::ScopeEntryDefinitionNode).getDefinition() = e and
|
||||
nodeFrom.asCfgNode() = def.getValue() and
|
||||
nodeFrom.asCfgNode() = def and
|
||||
var.getScope().getScope*() = nodeFrom.getScope()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -127,6 +127,11 @@ module Flow = Shared::Flow<Location, CaptureInput>;
|
||||
private Flow::ClosureNode asClosureNode(Node n) {
|
||||
result = n.(SynthCaptureNode).getSynthesizedCaptureNode()
|
||||
or
|
||||
exists(Comp comp | n = TSynthCompCapturedVariablesArgumentNode(comp) |
|
||||
result.(Flow::ExprNode).getExpr().getNode() = comp
|
||||
)
|
||||
or
|
||||
// TODO: Should the `Comp`s above be excluded here?
|
||||
result.(Flow::ExprNode).getExpr() = n.(CfgNode).getNode()
|
||||
or
|
||||
result.(Flow::VariableWriteSourceNode).getVariableWrite() = n.(CfgNode).getNode()
|
||||
|
||||
@@ -21,9 +21,169 @@ extensions:
|
||||
- ['argparse.ArgumentParser', 'Member[parse_args,parse_known_args].WithArity[0].ReturnValue', 'commandargs']
|
||||
|
||||
- ['os', 'Member[read].ReturnValue', 'file']
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["zipfile.ZipFile","Member[extractall].Argument[0,path:]", "path-injection"]
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ['argparse.ArgumentParser', 'Member[parse_args,parse_known_args]', 'Argument[0,args:]', 'ReturnValue', 'taint']
|
||||
# note: taint of attribute lookups is handled in QL
|
||||
# See https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser
|
||||
# note: taint flow for attribute lookups on `argparse.ArgumentParser` is handled in QL
|
||||
- ["argparse.ArgumentParser", "Member[_parse_known_args,_read_args_from_files]", "Argument[0,arg_strings:]", "ReturnValue", "taint"]
|
||||
- ["argparse.ArgumentParser", "Member[parse_args,parse_known_args]", "Argument[0,args:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/cgi.html#higher-level-interface
|
||||
- ["cgi.FieldStorage", "Member[getfirst,getlist,getvalue]", "Argument[self]", "ReturnValue", "taint"]
|
||||
# See
|
||||
# - https://docs.python.org/3/glossary.html#term-mapping
|
||||
# - https://docs.python.org/3/library/stdtypes.html#dict.get
|
||||
- ["collections.abc.Mapping", "Member[get]", "Argument[1,default:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/contextlib.html#contextlib.ExitStack
|
||||
- ["contextlib.ExitStack", "Member[enter_context]", "Argument[0,cm:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/copy.html#copy.deepcopy
|
||||
- ["copy", "Member[copy,deepcopy]", "Argument[0,x:]", "ReturnValue", "value"]
|
||||
# See
|
||||
# - https://docs.python.org/3/library/ctypes.html#ctypes.create_string_buffer
|
||||
# - https://docs.python.org/3/library/ctypes.html#ctypes.create_unicode_buffer
|
||||
- ["ctypes", "Member[create_string_buffer,create_unicode_buffer]", "Argument[0,init:,init_or_size:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3.11/distutils/apiref.html#distutils.util.change_root
|
||||
- ["distutils", "Member[util].Member[change_root]", "Argument[0,new_root:,1,pathname:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/email.header.html#email.header.Header
|
||||
- ["email.header.Header!", "Subclass.Call", "Argument[0,s:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/email.utils.html#email.utils.parseaddr
|
||||
- ["email", "Member[utils].Member[parseaddr]", "Argument[0,addr:]", "ReturnValue", "taint"]
|
||||
- ["email", "Member[utils].Member[parseaddr]", "Argument[0,addr:]", "ReturnValue.TupleElement[0,1]", "taint"]
|
||||
# See See https://docs.python.org/3/library/fnmatch.html#fnmatch.filter
|
||||
- ["fnmatch", "Member[filter]", "Argument[0,names:].ListElement", "ReturnValue.ListElement", "value"]
|
||||
- ["fnmatch", "Member[filter]", "Argument[0,names:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/getopt.html#getopt.getopt
|
||||
- ["getopt", "Member[getopt]", "Argument[0,args:]", "ReturnValue.TupleElement[1]", "taint"]
|
||||
- ["getopt", "Member[getopt]", "Argument[1,shortopts:,2,longopts:]", "ReturnValue.TupleElement[0].ListElement.TupleElement[0]", "taint"]
|
||||
# See https://docs.python.org/3/library/gettext.html#gettext.gettext
|
||||
- ["gettext", "Member[gettext]", "Argument[0,message:]", "ReturnValue", "taint"]
|
||||
# See
|
||||
# - https://docs.python.org/3/library/glob.html#glob.glob
|
||||
# - https://docs.python.org/3/library/glob.html#glob.iglob
|
||||
- ["glob", "Member[glob,iglob]", "Argument[0,pathname:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/gzip.html#gzip.GzipFile
|
||||
- ["gzip.GzipFile!", "Subclass.Call", "Argument[0,filename:]", "ReturnValue", "taint"]
|
||||
# See
|
||||
# - https://docs.python.org/3/library/html.html#html.escape
|
||||
# - https://docs.python.org/3/library/html.html#html.unescape
|
||||
- ["html", "Member[escape,unescape]", "Argument[0,s:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/html.parser.html#html.parser.HTMLParser.feed
|
||||
- ["html.parser.HTMLParser", "Member[feed]", "Argument[0,data:]", "Argument[self]", "taint"]
|
||||
# See https://docs.python.org/3.11/library/imp.html#imp.find_module
|
||||
- ["imp", "Member[find_module]", "Argument[0,name:,1,path:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/logging.html#logging.getLevelName
|
||||
# specifically the no matching case
|
||||
- ["logging", "Member[getLevelName]", "Argument[0,level:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/logging.html#logging.LogRecord.getMessage
|
||||
- ["logging.LogRecord", "Member[getMessage]", "Argument[self]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/mimetypes.html#mimetypes.guess_type
|
||||
- ["mimetypes", "Member[guess_type]", "Argument[0,url:]", "ReturnValue", "taint"]
|
||||
# See https://github.com/python/cpython/blob/main/Lib/nturl2path.py
|
||||
# No user-facing documentation, unfortunately.
|
||||
- ["nturl2path", "Member[pathname2url]", "Argument[0,p:]", "ReturnValue", "taint"]
|
||||
- ["nturl2path", "Member[url2pathname]", "Argument[0,url:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/optparse.html#optparse.OptionParser.parse_args
|
||||
- ["optparse.OptionParser", "Member[parse_args]", "Argument[0,args:,1,values:]", "ReturnValue.TupleElement[0,1]", "taint"]
|
||||
# See https://docs.python.org/3/library/os.html#os.walk
|
||||
- ["os", "Member[walk]", "Argument[0,top:]", "ReturnValue", "taint"]
|
||||
# See https://github.com/python/cpython/blob/3.10/Lib/pathlib.py#L972-L973
|
||||
- ["pathlib.Path", ".Member[__enter__]", "Argument[self]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/os.html#os.PathLike.__fspath__
|
||||
- ["pathlib.PurePath", "Member[__fspath__]", "Argument[self]", "ReturnValue", "taint"]
|
||||
# See
|
||||
# - https://docs.python.org/3/library/asyncio-queue.html#asyncio.Queue.get
|
||||
# - https://docs.python.org/3/library/asyncio-queue.html#asyncio.Queue.get_nowait
|
||||
- ["queue.Queue", "Member[get,get_nowait]", "Argument[self].ListElement", "ReturnValue", "value"]
|
||||
- ["queue.Queue", "Member[get,get_nowait]", "Argument[self]", "ReturnValue", "taint"]
|
||||
# See
|
||||
# - https://docs.python.org/3/library/asyncio-queue.html#asyncio.Queue.put
|
||||
# - https://docs.python.org/3/library/asyncio-queue.html#asyncio.Queue.put_nowait
|
||||
- ["queue.Queue", "Member[put,put_nowait]", "Argument[0,item:]", "Argument[self].ListElement", "value"]
|
||||
- ["queue.Queue", "Member[put,put_nowait]", "Argument[0,item:]", "Argument[self]", "taint"]
|
||||
# See
|
||||
# - https://docs.python.org/3/library/random.html#random.choice
|
||||
# - https://docs.python.org/3/library/random.html#module-random
|
||||
- ["random", "Member[choice]", "Argument[0,seq:].ListElement", "ReturnValue", "value"]
|
||||
- ["random", "Member[choice]", "Argument[0,seq:].SetElement", "ReturnValue", "value"]
|
||||
- ["random", "Member[choice]", "Argument[0,seq:]", "ReturnValue", "taint"]
|
||||
- ["random.Random", "Member[choice]", "Argument[0,seq:].ListElement", "ReturnValue", "value"]
|
||||
- ["random.Random", "Member[choice]", "Argument[0,seq:].SetElement", "ReturnValue", "value"]
|
||||
- ["random.Random", "Member[choice]", "Argument[0,seq:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/shlex.html#shlex.quote
|
||||
- ["shlex", "Member[quote]", "Argument[0,s:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/shutil.html#shutil.rmtree
|
||||
- ["shutil", "Member[rmtree]", "Argument[0,path:]", "Argument[2,onerror:,onexc:].Parameter[1]", "taint"]
|
||||
# See https://docs.python.org/3/library/shutil.html#shutil.which
|
||||
- ["shutil", "Member[which]", "Argument[0,cmd:,2,path:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/subprocess.html#subprocess.Popen
|
||||
- ["subprocess.Popen!", "Subclass.Call", "Argument[0,args:]", "ReturnValue", "taint"]
|
||||
# See
|
||||
# - https://docs.python.org/3/library/tarfile.html#tarfile.open
|
||||
# - https://docs.python.org/3/library/tarfile.html#tarfile.TarFile.open
|
||||
- ["tarfile", "Member[open]", "Argument[0,name:,2,fileobj:]", "ReturnValue", "taint"]
|
||||
- ["tarfile.TarFile", "Member[open]", "Argument[0,name:,2,fileobj:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/tempfile.html#tempfile.mkdtemp
|
||||
- ["tempfile", "Member[mkdtemp]", "Argument[0,suffix:,1,prefix:,2,dir:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/tempfile.html#tempfile.mkstemp
|
||||
- ["tempfile", "Member[mkstemp]", "Argument[0,suffix:,1,prefix:,2,dir:]", "ReturnValue.TupleElement[0,1]", "taint"]
|
||||
# See https://docs.python.org/3/library/textwrap.html#textwrap.dedent
|
||||
- ["textwrap", "Member[dedent]", "Argument[0,text:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/traceback.html#traceback.StackSummary.from_list
|
||||
- ["traceback.StackSummary", "Member[from_list]", "Argument[0,a_list:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/typing.html#typing.cast
|
||||
- ["typing", "Member[cast]", "Argument[1,val:]", "ReturnValue", "value"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.parse_qs
|
||||
- ["urllib", "Member[parse].Member[parse_qs]", "Argument[0,qs:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.quote
|
||||
- ["urllib", "Member[parse].Member[quote]", "Argument[0,string:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.quote_plus
|
||||
- ["urllib", "Member[parse].Member[quote_plus]", "Argument[0,string:]", "ReturnValue", "taint"]
|
||||
# See https://epydoc.sourceforge.net/stdlib/urllib-module.html
|
||||
- ["urllib", "Member[parse].Member[splitquery]", "Argument[0,url:]", "ReturnValue.TupleElement[0,1]", "taint"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.unquote
|
||||
- ["urllib", "Member[parse].Member[unquote]", "Argument[0,string:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.unquote_plus
|
||||
- ["urllib", "Member[parse].Member[unquote_plus]", "Argument[0,string:]", "ReturnValue", "taint"]
|
||||
# We could consider a more precise source than the first argument, namely tuple or dict content.
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode
|
||||
- ["urllib", "Member[parse].Member[urlencode]", "Argument[0,query:]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urljoin
|
||||
- ["urllib", "Member[parse].Member[urljoin]", "Argument[0,base:,1,url:]", "ReturnValue", "taint"]
|
||||
# See the internal documentation
|
||||
# https://github.com/python/cpython/blob/3.12/Lib/zipfile/_path/__init__.py#L103-L105
|
||||
- ["zipfile.CompleteDirs", "Member[namelist]", "Argument[self]", "ReturnValue", "taint"]
|
||||
# See https://docs.python.org/3/library/zipfile.html#zipfile.ZipFile
|
||||
# it may be necessary to read the code to understand the taint propagation
|
||||
# Constructor: https://github.com/python/cpython/blob/3.12/Lib/zipfile/__init__.py#L1266
|
||||
- ["zipfile.ZipFile!", "Subclass.Call", "Argument[0,file:]", "ReturnValue", "taint"]
|
||||
- ["zipfile.ZipFile!", "Subclass.Call", "Argument[0,file:]", "ReturnValue.Attribute[filelist].ListElement.Attribute[filename]", "value"]
|
||||
# _extract_member: https://github.com/python/cpython/blob/3.12/Lib/zipfile/__init__.py#L1761
|
||||
- ["zipfile.ZipFile", "Member[_extract_member]", "Argument[1,targetpath:]", "ReturnValue", "taint"]
|
||||
# infolist: https://github.com/python/cpython/blob/3.12/Lib/zipfile/__init__.py#L1498-L1501
|
||||
- ["zipfile.ZipFile", "Member[infolist]", "Argument[self]", "ReturnValue", "taint"]
|
||||
- ["zipfile.ZipFile", "Member[infolist]", "Argument[self].Attribute[filelist]", "ReturnValue", "value"]
|
||||
# namelist: https://github.com/python/cpython/blob/3.12/Lib/zipfile/__init__.py#L1494-L1496
|
||||
- ["zipfile.ZipFile", "Member[namelist]", "Argument[self]", "ReturnValue", "taint"]
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
extensible: neutralModel
|
||||
data: []
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
extensible: typeModel
|
||||
data: []
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/python-all
|
||||
extensible: typeVariableModel
|
||||
data: []
|
||||
@@ -254,10 +254,14 @@ module Stdlib {
|
||||
* See https://docs.python.org/3.9/library/logging.html#logging.Logger.
|
||||
*/
|
||||
module Logger {
|
||||
private import semmle.python.dataflow.new.internal.DataFlowDispatch as DD
|
||||
|
||||
/** Gets a reference to the `logging.Logger` class or any subclass. */
|
||||
API::Node subclassRef() {
|
||||
result = API::moduleImport("logging").getMember("Logger").getASubclass*()
|
||||
or
|
||||
result = API::moduleImport("logging").getMember("getLoggerClass").getReturn().getASubclass*()
|
||||
or
|
||||
result = ModelOutput::getATypeNode("logging.Logger~Subclass").getASubclass*()
|
||||
}
|
||||
|
||||
@@ -277,6 +281,13 @@ module Stdlib {
|
||||
ClassInstantiation() {
|
||||
this = subclassRef().getACall()
|
||||
or
|
||||
this =
|
||||
DD::selfTracker(subclassRef()
|
||||
.getAValueReachableFromSource()
|
||||
.asExpr()
|
||||
.(ClassExpr)
|
||||
.getInnerScope())
|
||||
or
|
||||
this = API::moduleImport("logging").getMember("root").asSource()
|
||||
or
|
||||
this = API::moduleImport("logging").getMember("getLogger").getACall()
|
||||
@@ -1492,6 +1503,9 @@ module StdlibPrivate {
|
||||
or
|
||||
// io.open is a special case, since it is an alias for the builtin `open`
|
||||
result = API::moduleImport("io").getMember("open")
|
||||
or
|
||||
// similarly, coecs.open calls the builtin `open`: https://github.com/python/cpython/blob/3.12/Lib/codecs.py#L918
|
||||
result = API::moduleImport("codecs").getMember("open")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3260,11 +3274,28 @@ module StdlibPrivate {
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
input in ["Argument[0]", "Argument[pattern:]"] and
|
||||
output = "ReturnValue.Attribute[pattern]" and
|
||||
preservesValue = true
|
||||
(
|
||||
output = "ReturnValue.Attribute[pattern]" and
|
||||
preservesValue = true
|
||||
or
|
||||
output = "ReturnValue" and
|
||||
preservesValue = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A base API node for regular expression functions.
|
||||
* Either the `re` module or a compiled regular expression.
|
||||
*/
|
||||
private API::Node re(boolean compiled) {
|
||||
result = API::moduleImport("re") and
|
||||
compiled = false
|
||||
or
|
||||
result = any(RePatternSummary c).getACall().(API::CallNode).getReturn() and
|
||||
compiled = true
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow summary for methods returning a `re.Match` object
|
||||
*
|
||||
@@ -3274,17 +3305,18 @@ module StdlibPrivate {
|
||||
ReMatchSummary() { this = ["re.Match", "compiled re.Match"] }
|
||||
|
||||
override DataFlow::CallCfgNode getACall() {
|
||||
this = "re.Match" and
|
||||
result = API::moduleImport("re").getMember(["match", "search", "fullmatch"]).getACall()
|
||||
or
|
||||
this = "compiled re.Match" and
|
||||
result =
|
||||
any(RePatternSummary c)
|
||||
.getACall()
|
||||
.(API::CallNode)
|
||||
.getReturn()
|
||||
.getMember(["match", "search", "fullmatch"])
|
||||
.getACall()
|
||||
exists(API::Node re, boolean compiled |
|
||||
re = re(compiled) and
|
||||
(
|
||||
compiled = false and
|
||||
this = "re.Match"
|
||||
or
|
||||
compiled = true and
|
||||
this = "compiled re.Match"
|
||||
)
|
||||
|
|
||||
result = re.getMember(["match", "search", "fullmatch"]).getACall()
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::ArgumentNode getACallback() { none() }
|
||||
@@ -3321,6 +3353,13 @@ module StdlibPrivate {
|
||||
}
|
||||
}
|
||||
|
||||
/** An API node for a `re.Match` object */
|
||||
private API::Node match() {
|
||||
result = any(ReMatchSummary c).getACall().(API::CallNode).getReturn()
|
||||
or
|
||||
result = re(_).getMember("finditer").getReturn().getASubscript()
|
||||
}
|
||||
|
||||
/**
|
||||
* A flow summary for methods on a `re.Match` object
|
||||
*
|
||||
@@ -3334,15 +3373,7 @@ module StdlibPrivate {
|
||||
methodName in ["expand", "group", "groups", "groupdict"]
|
||||
}
|
||||
|
||||
override DataFlow::CallCfgNode getACall() {
|
||||
result =
|
||||
any(ReMatchSummary c)
|
||||
.getACall()
|
||||
.(API::CallNode)
|
||||
.getReturn()
|
||||
.getMember(methodName)
|
||||
.getACall()
|
||||
}
|
||||
override DataFlow::CallCfgNode getACall() { result = match().getMember(methodName).getACall() }
|
||||
|
||||
override DataFlow::ArgumentNode getACallback() { none() }
|
||||
|
||||
@@ -3444,6 +3475,14 @@ module StdlibPrivate {
|
||||
) and
|
||||
preservesValue = false
|
||||
)
|
||||
or
|
||||
// flow from input string to attribute on match object
|
||||
exists(int arg | arg = methodName.(RegexExecutionMethod).getStringArgIndex() - offset |
|
||||
input in ["Argument[" + arg + "]", "Argument[string:]"] and
|
||||
methodName = "finditer" and
|
||||
output = "ReturnValue.ListElement.Attribute[string]" and
|
||||
preservesValue = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -4216,7 +4255,11 @@ module StdlibPrivate {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Flow summaries for functions contructing containers
|
||||
// ---------------------------------------------------------------------------
|
||||
/** A flow summary for `dict`. */
|
||||
/**
|
||||
* A flow summary for `dict`.
|
||||
*
|
||||
* see https://docs.python.org/3/library/stdtypes.html#dict
|
||||
*/
|
||||
class DictSummary extends SummarizedCallable {
|
||||
DictSummary() { this = "builtins.dict" }
|
||||
|
||||
@@ -4227,18 +4270,28 @@ module StdlibPrivate {
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
// The positional argument contains a mapping.
|
||||
// TODO: these values can be overwritten by keyword arguments
|
||||
// - dict mapping
|
||||
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
|
||||
input = "Argument[0].DictionaryElement[" + key + "]" and
|
||||
output = "ReturnValue.DictionaryElement[" + key + "]" and
|
||||
preservesValue = true
|
||||
)
|
||||
or
|
||||
// - list-of-pairs mapping
|
||||
input = "Argument[0].ListElement.TupleElement[1]" and
|
||||
output = "ReturnValue.DictionaryElementAny" and
|
||||
preservesValue = true
|
||||
or
|
||||
// The keyword arguments are added to the dictionary.
|
||||
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
|
||||
input = "Argument[" + key + ":]" and
|
||||
output = "ReturnValue.DictionaryElement[" + key + "]" and
|
||||
preservesValue = true
|
||||
)
|
||||
or
|
||||
// Imprecise content in the first argument ends up on the container itself.
|
||||
input = "Argument[0]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = false
|
||||
|
||||
@@ -45,6 +45,7 @@ module UnsafeShellCommandConstructionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node instanceof Sanitizer or
|
||||
node instanceof CommandInjection::Sanitizer // using all sanitizers from `py/command-injection`
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
## 1.3.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.3.0
|
||||
|
||||
### New Queries
|
||||
|
||||
* The `py/cors-misconfiguration-with-credentials` query, which finds insecure CORS middleware configurations.
|
||||
* The experimental `py/cors-misconfiguration-with-credentials` query, which finds insecure CORS middleware configurations.
|
||||
|
||||
## 1.2.2
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
### New Queries
|
||||
|
||||
* The `py/cors-misconfiguration-with-credentials` query, which finds insecure CORS middleware configurations.
|
||||
* The experimental `py/cors-misconfiguration-with-credentials` query, which finds insecure CORS middleware configurations.
|
||||
|
||||
3
python/ql/src/change-notes/released/1.3.1.md
Normal file
3
python/ql/src/change-notes/released/1.3.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.3.1
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.3.0
|
||||
lastReleaseVersion: 1.3.1
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @precision high
|
||||
* @id py/cors-misconfiguration-with-credentials
|
||||
* @tags security
|
||||
* experimental
|
||||
* external/cwe/cwe-942
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/python-queries
|
||||
version: 1.3.0
|
||||
version: 1.3.1
|
||||
groups:
|
||||
- python
|
||||
- queries
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
private import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.internal.TaintTrackingPrivate as TTP
|
||||
private import semmle.python.ApiGraphs
|
||||
|
||||
/**
|
||||
* Provides a data-flow configuration for detecting modifications of a parameters default value.
|
||||
@@ -73,7 +73,13 @@ module ModificationOfParameterWithDefault {
|
||||
or
|
||||
// the target of a copy step is (presumably) a different object, and hence modifications of
|
||||
// this object no longer matter for the purposes of this query.
|
||||
TTP::copyStep(_, node) and state in [true, false]
|
||||
copyTarget(node) and state in [true, false]
|
||||
}
|
||||
|
||||
private predicate copyTarget(DataFlow::Node node) {
|
||||
node = API::moduleImport("copy").getMember(["copy", "deepcopy"]).getACall()
|
||||
or
|
||||
node.(DataFlow::MethodCallNode).calls(_, "copy")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
| mapping | builtin-class collections.defaultdict |
|
||||
| mapping | builtin-class dict |
|
||||
| mapping | class MyDictSubclass |
|
||||
| mapping | class MyMappingABC |
|
||||
| mapping | class OrderedDict |
|
||||
| neither sequence nor mapping | builtin-class set |
|
||||
| neither sequence nor mapping | class MyMappingABC |
|
||||
| neither sequence nor mapping | class MySequenceABC |
|
||||
| sequence | builtin-class list |
|
||||
| sequence | builtin-class str |
|
||||
| sequence | builtin-class tuple |
|
||||
| sequence | builtin-class unicode |
|
||||
| sequence | class MySequenceABC |
|
||||
| sequence | class MySequenceImpl |
|
||||
|
||||
@@ -44,14 +44,10 @@
|
||||
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
|
||||
| test.py | 16 | ControlFlowNode for Attribute | class Y | ControlFlowNode for ClassExpr |
|
||||
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
|
||||
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | ControlFlowNode for ImportExpr |
|
||||
| test.py | 19 | ControlFlowNode for tty | Module tty | ControlFlowNode for ImportExpr |
|
||||
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | ControlFlowNode for from sys import * |
|
||||
| test.py | 22 | ControlFlowNode for x | Module package.x | Entry node for Module package.x |
|
||||
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 24 | ControlFlowNode for argv | int 0 | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
|
||||
| test.py | 31 | ControlFlowNode for argv | list object | ControlFlowNode for from sys import * |
|
||||
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | ControlFlowNode for ImportExpr |
|
||||
| test.py | 34 | ControlFlowNode for timeout | builtin-class socket.timeout | ControlFlowNode for from _socket import * |
|
||||
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
|
||||
|
||||
@@ -44,14 +44,10 @@
|
||||
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
|
||||
| test.py | 16 | ControlFlowNode for Attribute | class Y | builtin-class type | ControlFlowNode for ClassExpr |
|
||||
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
|
||||
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 19 | ControlFlowNode for tty | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | builtin-class builtin_function_or_method | ControlFlowNode for from sys import * |
|
||||
| test.py | 22 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x |
|
||||
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 24 | ControlFlowNode for argv | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 31 | ControlFlowNode for argv | list object | builtin-class list | ControlFlowNode for from sys import * |
|
||||
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 34 | ControlFlowNode for timeout | builtin-class socket.timeout | builtin-class type | ControlFlowNode for from _socket import * |
|
||||
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| six | Package six |
|
||||
| six.moves | Package six.moves |
|
||||
| six.moves.http_client | Module httplib |
|
||||
| six.moves.http_client.HTTPConnection | class HTTPConnection |
|
||||
| six.moves.http_client | Missing module httplib |
|
||||
| six.moves.http_client.HTTPConnection | Missing module attribute httplib.HTTPConnection |
|
||||
| six.moves.range | builtin-class xrange |
|
||||
| six.moves.urllib | Package six.moves.urllib |
|
||||
| six.moves.urllib.parse | Module six.moves.urllib_parse |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| 38 |
|
||||
| 11 |
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
| mapping | builtin-class collections.OrderedDict |
|
||||
| mapping | builtin-class collections.defaultdict |
|
||||
| mapping | builtin-class dict |
|
||||
| mapping | class MyDictSubclass |
|
||||
| mapping | class MyMappingABC |
|
||||
| mapping | class OrderedDict |
|
||||
| neither sequence nor mapping | builtin-class set |
|
||||
| sequence | builtin-class bytes |
|
||||
| sequence | builtin-class list |
|
||||
|
||||
@@ -44,14 +44,10 @@
|
||||
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
|
||||
| test.py | 16 | ControlFlowNode for Attribute | class Y | ControlFlowNode for ClassExpr |
|
||||
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | Entry node for Module package.moduleX |
|
||||
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | ControlFlowNode for ImportExpr |
|
||||
| test.py | 19 | ControlFlowNode for tty | Module tty | ControlFlowNode for ImportExpr |
|
||||
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | ControlFlowNode for from sys import * |
|
||||
| test.py | 22 | ControlFlowNode for x | Module package.x | Entry node for Module package.x |
|
||||
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 24 | ControlFlowNode for argv | int 0 | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
|
||||
| test.py | 31 | ControlFlowNode for argv | list object | ControlFlowNode for from sys import * |
|
||||
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | ControlFlowNode for ImportExpr |
|
||||
| test.py | 34 | ControlFlowNode for timeout | builtin-class TimeoutError | ControlFlowNode for from _socket import * |
|
||||
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | ControlFlowNode for ImportExpr |
|
||||
|
||||
@@ -44,14 +44,10 @@
|
||||
| test.py | 15 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
|
||||
| test.py | 16 | ControlFlowNode for Attribute | class Y | builtin-class type | ControlFlowNode for ClassExpr |
|
||||
| test.py | 16 | ControlFlowNode for moduleX | Module package.moduleX | builtin-class module | Entry node for Module package.moduleX |
|
||||
| test.py | 19 | ControlFlowNode for ImportExpr | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 19 | ControlFlowNode for tty | Module tty | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 22 | ControlFlowNode for Attribute | Builtin-function exc_info | builtin-class builtin_function_or_method | ControlFlowNode for from sys import * |
|
||||
| test.py | 22 | ControlFlowNode for x | Module package.x | builtin-class module | Entry node for Module package.x |
|
||||
| test.py | 24 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 24 | ControlFlowNode for argv | int 0 | builtin-class int | ControlFlowNode for IntegerLiteral |
|
||||
| test.py | 27 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 31 | ControlFlowNode for argv | list object | builtin-class list | ControlFlowNode for from sys import * |
|
||||
| test.py | 33 | ControlFlowNode for ImportExpr | Module socket | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
| test.py | 34 | ControlFlowNode for timeout | builtin-class TimeoutError | builtin-class type | ControlFlowNode for from _socket import * |
|
||||
| x.py | 2 | ControlFlowNode for ImportExpr | Module sys | builtin-class module | ControlFlowNode for ImportExpr |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
| mwe_failure.py:7:1:7:23 | class MyTest | <MISSING BASE TYPE> |
|
||||
| mwe_failure_2.py:7:1:7:23 | class MyTest | <MISSING BASE TYPE> |
|
||||
| mwe_failure.py:7:1:7:23 | class MyTest | class TestCase |
|
||||
| mwe_failure_2.py:7:1:7:23 | class MyTest | class TestCase |
|
||||
| mwe_success.py:7:1:7:23 | class MyTest | class TestCase |
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
| Module package.assistant | e | Wrong() |
|
||||
| Module package.assistant | f | int 1 |
|
||||
| Module package.helper | __name__ | str u'package.helper' |
|
||||
| Module package.helper | absolute_import | _Feature() |
|
||||
| Module package.helper | assistant | Module package.assistant |
|
||||
| Module package.helper | d | int 4 |
|
||||
| Module package.helper | e | int 5 |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| six | Package six |
|
||||
| six.moves | Package six.moves |
|
||||
| six.moves.http_client | Module http.client |
|
||||
| six.moves.http_client.HTTPConnection | class HTTPConnection |
|
||||
| six.moves.http_client | Missing module http.client |
|
||||
| six.moves.http_client.HTTPConnection | Missing module attribute http.client.HTTPConnection |
|
||||
| six.moves.range | builtin-class range |
|
||||
| six.moves.urllib | Package six.moves.urllib |
|
||||
| six.moves.urllib.parse | Module six.moves.urllib_parse |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| 51 |
|
||||
| 11 |
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
| UndefinedExport.py:3:18:3:20 | StringLiteral | The name 'y' is exported by __all__ but is not defined. |
|
||||
| UndefinedExport.py:3:23:3:25 | StringLiteral | The name 'z' is exported by __all__ but is not defined. |
|
||||
| UndefinedExport.py:3:28:3:35 | StringLiteral | The name 'module' is exported by __all__ but is not defined. |
|
||||
| enum_convert.py:8:13:8:19 | StringLiteral | The name 'Maybe' is exported by __all__ but is not defined. |
|
||||
| enum_convert.py:8:22:8:32 | StringLiteral | The name 'Maybe_not' is exported by __all__ but is not defined. |
|
||||
| package/__init__.py:1:23:1:34 | StringLiteral | The name 'not_exists' is exported by __all__ but is not defined. |
|
||||
|
||||
@@ -65,7 +65,7 @@ string getCallEdgeValue(CallNode call, Function target) {
|
||||
else
|
||||
exists(string fixedRelativePath |
|
||||
fixedRelativePath =
|
||||
target.getLocation().getFile().getRelativePath().regexpCapture(".*/CallGraph[^/]*/(.*)", 1)
|
||||
target.getLocation().getFile().getAbsolutePath().regexpCapture(".*/CallGraph[^/]*/(.*)", 1)
|
||||
|
|
||||
// the value needs to be enclosed in quotes to allow special characters
|
||||
result = "\"" + fixedRelativePath + ":" + betterQualName(target) + "\""
|
||||
|
||||
@@ -34,7 +34,9 @@ edges
|
||||
| TarSlipImprov.py:142:9:142:13 | ControlFlowNode for entry | TarSlipImprov.py:143:36:143:40 | ControlFlowNode for entry | provenance | |
|
||||
| TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | provenance | |
|
||||
| TarSlipImprov.py:151:22:151:49 | ControlFlowNode for Attribute() | TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | provenance | Config |
|
||||
| TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield | provenance | |
|
||||
| TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | provenance | |
|
||||
| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | provenance | |
|
||||
| TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | provenance | |
|
||||
| TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | TarSlipImprov.py:162:20:162:23 | ControlFlowNode for tarc | provenance | |
|
||||
| TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | provenance | |
|
||||
@@ -131,6 +133,7 @@ nodes
|
||||
| TarSlipImprov.py:151:14:151:50 | ControlFlowNode for closing() | semmle.label | ControlFlowNode for closing() |
|
||||
| TarSlipImprov.py:151:22:151:49 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| TarSlipImprov.py:151:55:151:56 | ControlFlowNode for tf | semmle.label | ControlFlowNode for tf |
|
||||
| TarSlipImprov.py:152:13:152:20 | ControlFlowNode for Yield | semmle.label | ControlFlowNode for Yield |
|
||||
| TarSlipImprov.py:152:19:152:20 | ControlFlowNode for tf | semmle.label | ControlFlowNode for tf |
|
||||
| TarSlipImprov.py:157:9:157:14 | ControlFlowNode for tar_cm | semmle.label | ControlFlowNode for tar_cm |
|
||||
| TarSlipImprov.py:157:18:157:40 | ControlFlowNode for py2_tarxz() | semmle.label | ControlFlowNode for py2_tarxz() |
|
||||
|
||||
@@ -75,6 +75,7 @@ edges
|
||||
| UnsafeUnpack.py:161:19:161:21 | ControlFlowNode for tar | UnsafeUnpack.py:163:33:163:35 | ControlFlowNode for tar | provenance | |
|
||||
| UnsafeUnpack.py:161:25:161:46 | ControlFlowNode for Attribute() | UnsafeUnpack.py:161:19:161:21 | ControlFlowNode for tar | provenance | |
|
||||
| UnsafeUnpack.py:161:38:161:45 | ControlFlowNode for savepath | UnsafeUnpack.py:161:25:161:46 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| UnsafeUnpack.py:161:38:161:45 | ControlFlowNode for savepath | UnsafeUnpack.py:161:25:161:46 | ControlFlowNode for Attribute() | provenance | MaD:69 |
|
||||
| UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | UnsafeUnpack.py:166:37:166:42 | ControlFlowNode for member | provenance | |
|
||||
| UnsafeUnpack.py:163:33:163:35 | ControlFlowNode for tar | UnsafeUnpack.py:163:23:163:28 | ControlFlowNode for member | provenance | |
|
||||
| UnsafeUnpack.py:166:23:166:28 | [post] ControlFlowNode for result | UnsafeUnpack.py:167:67:167:72 | ControlFlowNode for result | provenance | |
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
edges
|
||||
| test.py:10:16:10:24 | ControlFlowNode for file_path | test.py:11:21:11:29 | ControlFlowNode for file_path | provenance | |
|
||||
| test.py:11:5:11:35 | ControlFlowNode for Attribute() | test.py:11:5:11:52 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:11:21:11:29 | ControlFlowNode for file_path | test.py:11:5:11:35 | ControlFlowNode for Attribute() | provenance | MaD:85 |
|
||||
| test.py:11:21:11:29 | ControlFlowNode for file_path | test.py:11:5:11:52 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:11:21:11:29 | ControlFlowNode for file_path | test.py:12:21:12:29 | ControlFlowNode for file_path | provenance | |
|
||||
| test.py:12:5:12:35 | ControlFlowNode for Attribute() | test.py:12:5:12:48 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:12:21:12:29 | ControlFlowNode for file_path | test.py:12:5:12:35 | ControlFlowNode for Attribute() | provenance | MaD:85 |
|
||||
| test.py:12:21:12:29 | ControlFlowNode for file_path | test.py:12:5:12:48 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:12:21:12:29 | ControlFlowNode for file_path | test.py:14:26:14:34 | ControlFlowNode for file_path | provenance | |
|
||||
| test.py:14:10:14:35 | ControlFlowNode for Attribute() | test.py:15:14:15:29 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:14:26:14:34 | ControlFlowNode for file_path | test.py:14:10:14:35 | ControlFlowNode for Attribute() | provenance | MaD:85 |
|
||||
| test.py:14:26:14:34 | ControlFlowNode for file_path | test.py:15:14:15:29 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:14:26:14:34 | ControlFlowNode for file_path | test.py:18:26:18:34 | ControlFlowNode for file_path | provenance | |
|
||||
| test.py:18:10:18:35 | ControlFlowNode for Attribute() | test.py:19:14:19:39 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:18:26:18:34 | ControlFlowNode for file_path | test.py:18:10:18:35 | ControlFlowNode for Attribute() | provenance | MaD:85 |
|
||||
| test.py:18:26:18:34 | ControlFlowNode for file_path | test.py:19:14:19:39 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:18:26:18:34 | ControlFlowNode for file_path | test.py:22:21:22:29 | ControlFlowNode for file_path | provenance | |
|
||||
| test.py:22:5:22:30 | ControlFlowNode for Attribute() | test.py:22:5:22:60 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:22:21:22:29 | ControlFlowNode for file_path | test.py:22:5:22:30 | ControlFlowNode for Attribute() | provenance | MaD:85 |
|
||||
| test.py:22:21:22:29 | ControlFlowNode for file_path | test.py:22:5:22:60 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
| test.py:22:21:22:29 | ControlFlowNode for file_path | test.py:24:18:24:26 | ControlFlowNode for file_path | provenance | |
|
||||
| test.py:24:18:24:26 | ControlFlowNode for file_path | test.py:24:5:24:52 | ControlFlowNode for Attribute() | provenance | Config |
|
||||
@@ -37,14 +47,19 @@ edges
|
||||
| test.py:28:26:28:34 | ControlFlowNode for file_path | test.py:64:36:64:44 | ControlFlowNode for file_path | provenance | |
|
||||
nodes
|
||||
| test.py:10:16:10:24 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path |
|
||||
| test.py:11:5:11:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:11:5:11:52 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:11:21:11:29 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path |
|
||||
| test.py:12:5:12:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:12:5:12:48 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:12:21:12:29 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path |
|
||||
| test.py:14:10:14:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:14:26:14:34 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path |
|
||||
| test.py:15:14:15:29 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:18:10:18:35 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:18:26:18:34 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path |
|
||||
| test.py:19:14:19:39 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:22:5:22:30 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:22:5:22:60 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
| test.py:22:21:22:29 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path |
|
||||
| test.py:24:5:24:52 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
| options.all | False |
|
||||
| options.colorize | True |
|
||||
| options.context_cost | 11 |
|
||||
| options.extract_stdlib | True |
|
||||
| options.extract_stdlib | False |
|
||||
| options.guess | False |
|
||||
| options.help | False |
|
||||
| options.ignore_missing_modules | False |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
| 1 | ControlFlowNode for functools | Module functools | test.py:1 |
|
||||
| 3 | ControlFlowNode for annotate | Function annotate | test.py:3 |
|
||||
| 4 | ControlFlowNode for inner | Function inner | test.py:4 |
|
||||
| 5 | ControlFlowNode for func | Function func1 | test.py:23 |
|
||||
@@ -11,7 +10,6 @@
|
||||
| 13 | ControlFlowNode for wrapper | Function wrapper | test.py:10 |
|
||||
| 15 | ControlFlowNode for wraps2 | Function wraps2 | test.py:15 |
|
||||
| 16 | ControlFlowNode for func | Function func3 | test.py:31 |
|
||||
| 16 | ControlFlowNode for functools | Module functools | test.py:1 |
|
||||
| 17 | ControlFlowNode for args | args | test.py:17 |
|
||||
| 17 | ControlFlowNode for wrapper | Attribute()() | test.py:16 |
|
||||
| 18 | ControlFlowNode for args | args | test.py:17 |
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
| test.py:11:21:11:24 | ControlFlowNode for args | runtime | instance of tuple |
|
||||
| test.py:13:12:13:18 | ControlFlowNode for wrapper | runtime | Function wraps1.wrapper |
|
||||
| test.py:13:12:13:18 | ControlFlowNode for wrapper | test.py:26 from import | Function wraps1.wrapper |
|
||||
| test.py:16:6:16:14 | ControlFlowNode for functools | runtime | Module functools |
|
||||
| test.py:16:6:16:14 | ControlFlowNode for functools | test.py:30 from import | Module functools |
|
||||
| test.py:16:6:16:14 | ControlFlowNode for functools | runtime | Missing module functools |
|
||||
| test.py:16:6:16:14 | ControlFlowNode for functools | test.py:30 from import | Missing module functools |
|
||||
| test.py:16:22:16:25 | ControlFlowNode for func | runtime | Unknown value |
|
||||
| test.py:16:22:16:25 | ControlFlowNode for func | test.py:30 from import | Function func3 |
|
||||
| test.py:18:21:18:24 | ControlFlowNode for args | runtime | instance of tuple |
|
||||
|
||||
@@ -87,10 +87,6 @@
|
||||
| Module pointsto_test | 69 | ControlFlowNode for X | class X |
|
||||
| Module pointsto_test | 70 | ControlFlowNode for Attribute | deco() |
|
||||
| Module pointsto_test | 70 | ControlFlowNode for X | class X |
|
||||
| Module pointsto_test | 72 | ControlFlowNode for ImportExpr | Module abc |
|
||||
| Module pointsto_test | 72 | ControlFlowNode for ImportMember | Function abstractmethod |
|
||||
| Module pointsto_test | 72 | ControlFlowNode for abstractmethod | Function abstractmethod |
|
||||
| Module pointsto_test | 73 | ControlFlowNode for abstractmethod | Function abstractmethod |
|
||||
| Module pointsto_test | 75 | ControlFlowNode for C | class C |
|
||||
| Module pointsto_test | 75 | ControlFlowNode for C() | C() |
|
||||
| Module pointsto_test | 75 | ControlFlowNode for type | builtin-class type |
|
||||
|
||||
@@ -95,10 +95,6 @@
|
||||
| 69 | ControlFlowNode for X | class X |
|
||||
| 70 | ControlFlowNode for Attribute | deco() |
|
||||
| 70 | ControlFlowNode for X | class X |
|
||||
| 72 | ControlFlowNode for ImportExpr | Module abc |
|
||||
| 72 | ControlFlowNode for ImportMember | Function abstractmethod |
|
||||
| 72 | ControlFlowNode for abstractmethod | Function abstractmethod |
|
||||
| 73 | ControlFlowNode for abstractmethod | Function abstractmethod |
|
||||
| 75 | ControlFlowNode for C | class C |
|
||||
| 75 | ControlFlowNode for C() | C() |
|
||||
| 75 | ControlFlowNode for type | builtin-class type |
|
||||
|
||||
@@ -95,10 +95,6 @@
|
||||
| 69 | ControlFlowNode for Attribute | Attribute | builtin-class method |
|
||||
| 69 | ControlFlowNode for X | class X | builtin-class type |
|
||||
| 70 | ControlFlowNode for X | class X | builtin-class type |
|
||||
| 72 | ControlFlowNode for ImportExpr | Module abc | builtin-class module |
|
||||
| 72 | ControlFlowNode for ImportMember | Function abstractmethod | builtin-class function |
|
||||
| 72 | ControlFlowNode for abstractmethod | Function abstractmethod | builtin-class function |
|
||||
| 73 | ControlFlowNode for abstractmethod | Function abstractmethod | builtin-class function |
|
||||
| 75 | ControlFlowNode for C | class C | builtin-class type |
|
||||
| 75 | ControlFlowNode for C() | C() | class C |
|
||||
| 75 | ControlFlowNode for type | builtin-class type | builtin-class type |
|
||||
|
||||
@@ -70,7 +70,3 @@
|
||||
| type_test.py | 55 | ControlFlowNode for arg | class E | 29 |
|
||||
| type_test.py | 67 | ControlFlowNode for x | float 1.0 | 62 |
|
||||
| type_test.py | 67 | ControlFlowNode for x | int 0 | 62 |
|
||||
| type_test.py | 77 | ControlFlowNode for IntegerLiteral | int 0 | 77 |
|
||||
| type_test.py | 83 | ControlFlowNode for IntegerLiteral | int 0 | 83 |
|
||||
| type_test.py | 89 | ControlFlowNode for IntegerLiteral | int 0 | 89 |
|
||||
| type_test.py | 95 | ControlFlowNode for IntegerLiteral | int 0 | 95 |
|
||||
|
||||
@@ -70,7 +70,3 @@
|
||||
| type_test.py | 55 | ControlFlowNode for arg | class E | builtin-class type | 29 |
|
||||
| type_test.py | 67 | ControlFlowNode for x | float 1.0 | builtin-class float | 62 |
|
||||
| type_test.py | 67 | ControlFlowNode for x | int 0 | builtin-class int | 62 |
|
||||
| type_test.py | 77 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 77 |
|
||||
| type_test.py | 83 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 83 |
|
||||
| type_test.py | 89 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 89 |
|
||||
| type_test.py | 95 | ControlFlowNode for IntegerLiteral | int 0 | builtin-class int | 95 |
|
||||
|
||||
@@ -85,15 +85,12 @@
|
||||
| h_classes.py:23 | Class Base | __init__ | Function __init__ |
|
||||
| h_classes.py:48 | Class D | m | Function f |
|
||||
| h_classes.py:48 | Class D | n | Function n |
|
||||
| i_imports.py:0 | Module code.i_imports | BytesIO | builtin-class _io.BytesIO |
|
||||
| i_imports.py:0 | Module code.i_imports | StringIO | builtin-class _io.StringIO |
|
||||
| i_imports.py:0 | Module code.i_imports | _io | Module _io |
|
||||
| i_imports.py:0 | Module code.i_imports | a | int 1 |
|
||||
| i_imports.py:0 | Module code.i_imports | argv | list object |
|
||||
| i_imports.py:0 | Module code.i_imports | b | int 2 |
|
||||
| i_imports.py:0 | Module code.i_imports | c | int 3 |
|
||||
| i_imports.py:0 | Module code.i_imports | code | Module code |
|
||||
| i_imports.py:0 | Module code.i_imports | io | Module io |
|
||||
| i_imports.py:0 | Module code.i_imports | module1 | Module code.test_package.module1 |
|
||||
| i_imports.py:0 | Module code.i_imports | module2 | Module code.test_package.module2 |
|
||||
| i_imports.py:0 | Module code.i_imports | p | int 1 |
|
||||
|
||||
@@ -475,14 +475,6 @@
|
||||
| i_imports.py:31 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 31 | import |
|
||||
| i_imports.py:31 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 31 | import |
|
||||
| i_imports.py:31 | ControlFlowNode for _io | Module _io | builtin-class module | 29 | import |
|
||||
| i_imports.py:33 | ControlFlowNode for ImportExpr | Module io | builtin-class module | 33 | import |
|
||||
| i_imports.py:33 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
|
||||
| i_imports.py:34 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 55 | import |
|
||||
| i_imports.py:34 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 55 | import |
|
||||
| i_imports.py:34 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
|
||||
| i_imports.py:35 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 55 | import |
|
||||
| i_imports.py:35 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 55 | import |
|
||||
| i_imports.py:35 | ControlFlowNode for io | Module io | builtin-class module | 33 | import |
|
||||
| i_imports.py:37 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 37 | import |
|
||||
| i_imports.py:37 | ControlFlowNode for code | Module code | builtin-class module | 37 | import |
|
||||
| i_imports.py:38 | ControlFlowNode for Attribute | Function f2 | builtin-class function | 24 | import |
|
||||
|
||||
@@ -572,14 +572,6 @@
|
||||
| i_imports.py:31 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 31 |
|
||||
| i_imports.py:31 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 31 |
|
||||
| i_imports.py:31 | ControlFlowNode for _io | Module _io | builtin-class module | 29 |
|
||||
| i_imports.py:33 | ControlFlowNode for ImportExpr | Module io | builtin-class module | 33 |
|
||||
| i_imports.py:33 | ControlFlowNode for io | Module io | builtin-class module | 33 |
|
||||
| i_imports.py:34 | ControlFlowNode for Attribute | builtin-class _io.StringIO | builtin-class type | 55 |
|
||||
| i_imports.py:34 | ControlFlowNode for StringIO | builtin-class _io.StringIO | builtin-class type | 55 |
|
||||
| i_imports.py:34 | ControlFlowNode for io | Module io | builtin-class module | 33 |
|
||||
| i_imports.py:35 | ControlFlowNode for Attribute | builtin-class _io.BytesIO | builtin-class type | 55 |
|
||||
| i_imports.py:35 | ControlFlowNode for BytesIO | builtin-class _io.BytesIO | builtin-class type | 55 |
|
||||
| i_imports.py:35 | ControlFlowNode for io | Module io | builtin-class module | 33 |
|
||||
| i_imports.py:37 | ControlFlowNode for ImportExpr | Module code | builtin-class module | 37 |
|
||||
| i_imports.py:37 | ControlFlowNode for code | Module code | builtin-class module | 37 |
|
||||
| i_imports.py:38 | ControlFlowNode for Attribute | Function f2 | builtin-class function | 24 |
|
||||
|
||||
@@ -373,11 +373,9 @@
|
||||
| i_imports.py:30 | ControlFlowNode for _io | import | Module _io | builtin-class module |
|
||||
| i_imports.py:31 | ControlFlowNode for Attribute | import | builtin-class _io.BytesIO | builtin-class type |
|
||||
| i_imports.py:31 | ControlFlowNode for _io | import | Module _io | builtin-class module |
|
||||
| i_imports.py:33 | ControlFlowNode for ImportExpr | import | Module io | builtin-class module |
|
||||
| i_imports.py:34 | ControlFlowNode for Attribute | import | builtin-class _io.StringIO | builtin-class type |
|
||||
| i_imports.py:34 | ControlFlowNode for io | import | Module io | builtin-class module |
|
||||
| i_imports.py:35 | ControlFlowNode for Attribute | import | builtin-class _io.BytesIO | builtin-class type |
|
||||
| i_imports.py:35 | ControlFlowNode for io | import | Module io | builtin-class module |
|
||||
| i_imports.py:33 | ControlFlowNode for ImportExpr | import | Missing module io | builtin-class module |
|
||||
| i_imports.py:34 | ControlFlowNode for io | import | Missing module io | builtin-class module |
|
||||
| i_imports.py:35 | ControlFlowNode for io | import | Missing module io | builtin-class module |
|
||||
| i_imports.py:37 | ControlFlowNode for ImportExpr | import | Package code | builtin-class module |
|
||||
| i_imports.py:38 | ControlFlowNode for Attribute | import | Function f2 | builtin-class function |
|
||||
| i_imports.py:38 | ControlFlowNode for Attribute | import | Module code.n_nesting | builtin-class module |
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
| Local module | code-invalid-package-name/cmd.py:0:0:0:0 | Module cmd | referenced in external file called | pdb.py |
|
||||
| Local module | code-invalid-package-name/cmd.py:0:0:0:0 | Module cmd | referenced in local file called | test_ok.py |
|
||||
| Local module | code-invalid-package-name/unique_name.py:0:0:0:0 | Module unique_name | referenced in local file called | unique_name_use.py |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
| Module 'cmd' (local, not in stdlib, not missing) referenced in local file | code-invalid-package-name/test_ok.py:1 |
|
||||
| Module 'pdb' (external, in stdlib, not missing) referenced in local file | code-invalid-package-name/test_fail.py:3 |
|
||||
| Module 'pdb' (external, not in stdlib, missing) referenced in local file | code-invalid-package-name/test_fail.py:3 |
|
||||
| Module 'unique_name' (local, not in stdlib, not missing) referenced in local file | code-invalid-package-name/unique_name_use.py:1 |
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
testFailures
|
||||
| classes.py:54:44:54:107 | Comment #$ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result:arg1="with_length_hint" |
|
||||
| classes.py:54:44:54:107 | Comment #$ arg1="with_length_hint" func=With_length_hint.__length_hint__ | Missing result:func=With_length_hint.__length_hint__ |
|
||||
| classes.py:71:32:71:77 | Comment #$ arg1="with_index" func=With_index.__index__ | Missing result:arg1="with_index" |
|
||||
| classes.py:71:32:71:77 | Comment #$ arg1="with_index" func=With_index.__index__ | Missing result:func=With_index.__index__ |
|
||||
failures
|
||||
|
||||
@@ -8,9 +8,4 @@
|
||||
| test.py:208:1:208:53 | Entry definition for SsaSourceVariable SINK | test.py:210:5:210:8 | ControlFlowNode for SINK |
|
||||
| test.py:208:1:208:53 | Entry definition for SsaSourceVariable SOURCE | test.py:209:25:209:30 | ControlFlowNode for SOURCE |
|
||||
| test.py:209:5:209:5 | ControlFlowNode for x | test.py:210:10:210:10 | ControlFlowNode for x |
|
||||
| test.py:209:9:209:68 | ControlFlowNode for .0 | test.py:209:9:209:68 | ControlFlowNode for .0 |
|
||||
| test.py:209:9:209:68 | ControlFlowNode for ListComp | test.py:209:5:209:5 | ControlFlowNode for x |
|
||||
| test.py:209:16:209:16 | ControlFlowNode for v | test.py:209:45:209:45 | ControlFlowNode for v |
|
||||
| test.py:209:40:209:40 | ControlFlowNode for u | test.py:209:56:209:56 | ControlFlowNode for u |
|
||||
| test.py:209:51:209:51 | ControlFlowNode for z | test.py:209:67:209:67 | ControlFlowNode for z |
|
||||
| test.py:209:62:209:62 | ControlFlowNode for y | test.py:209:10:209:10 | ControlFlowNode for y |
|
||||
|
||||
@@ -137,7 +137,7 @@ def test_list_comprehension_with_tuple_result():
|
||||
s = SOURCE
|
||||
ns = NONSOURCE
|
||||
l3 = [(s, ns) for _ in [1]]
|
||||
SINK(l3[0][0]) # $ MISSING: flow="SOURCE, l:-3 -> l3[0][0]"
|
||||
SINK(l3[0][0]) # $ flow="SOURCE, l:-3 -> l3[0][0]"
|
||||
SINK_F(l3[0][1])
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ def gen(x):
|
||||
|
||||
def test_yield():
|
||||
g = gen(SOURCE)
|
||||
SINK(next(g)) #$ MISSING:flow="SOURCE, l:-1 -> next()"
|
||||
SINK(next(g)) #$ flow="SOURCE, l:-1 -> next(..)"
|
||||
|
||||
|
||||
def gen_from(x):
|
||||
@@ -260,7 +260,7 @@ def test_yield_from():
|
||||
# a statement rather than an expression, but related to generators
|
||||
def test_for():
|
||||
for x in gen(SOURCE):
|
||||
SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x"
|
||||
SINK(x) #$ flow="SOURCE, l:-1 -> x"
|
||||
|
||||
|
||||
# 6.2.9.1. Generator-iterator methods
|
||||
|
||||
@@ -132,8 +132,8 @@ def test_dict_from_keyword():
|
||||
@expects(2)
|
||||
def test_dict_from_list():
|
||||
d = dict([("k", SOURCE), ("k1", NONSOURCE)])
|
||||
SINK(d["k"]) #$ MISSING: flow="SOURCE, l:-1 -> d[k]"
|
||||
SINK_F(d["k1"])
|
||||
SINK(d["k"]) #$ flow="SOURCE, l:-1 -> d['k']"
|
||||
SINK_F(d["k1"]) #$ SPURIOUS: flow="SOURCE, l:-2 -> d['k1']" // due to imprecise list content
|
||||
|
||||
@expects(2)
|
||||
def test_dict_from_dict():
|
||||
@@ -142,6 +142,14 @@ def test_dict_from_dict():
|
||||
SINK(d2["k"]) #$ flow="SOURCE, l:-2 -> d2['k']"
|
||||
SINK_F(d2["k1"])
|
||||
|
||||
@expects(4)
|
||||
def test_dict_from_multiple_args():
|
||||
d = dict([("k", SOURCE), ("k1", NONSOURCE)], k2 = SOURCE, k3 = NONSOURCE)
|
||||
SINK(d["k"]) #$ flow="SOURCE, l:-1 -> d['k']"
|
||||
SINK_F(d["k1"]) #$ SPURIOUS: flow="SOURCE, l:-2 -> d['k1']" // due to imprecise list content
|
||||
SINK(d["k2"]) #$ flow="SOURCE, l:-3 -> d['k2']"
|
||||
SINK_F(d["k3"]) #$ SPURIOUS: flow="SOURCE, l:-4 -> d['k3']" // due to imprecise list content
|
||||
|
||||
## Container methods
|
||||
|
||||
### List
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
| generator.py:0:0:0:0 | Module generator | generator.py:1:1:1:23 | ControlFlowNode for FunctionExpr |
|
||||
| generator.py:0:0:0:0 | Module generator | generator.py:1:5:1:18 | ControlFlowNode for generator_func |
|
||||
| generator.py:1:1:1:23 | Function generator_func | generator.py:1:20:1:21 | ControlFlowNode for xs |
|
||||
| generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for .0 |
|
||||
| generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for .0 |
|
||||
| generator.py:1:1:1:23 | Function generator_func | generator.py:2:12:2:26 | ControlFlowNode for ListComp |
|
||||
| generator.py:1:1:1:23 | Function generator_func | generator.py:2:13:2:13 | ControlFlowNode for Yield |
|
||||
| generator.py:1:1:1:23 | Function generator_func | generator.py:2:13:2:13 | ControlFlowNode for x |
|
||||
| generator.py:1:1:1:23 | Function generator_func | generator.py:2:19:2:19 | ControlFlowNode for x |
|
||||
| generator.py:1:1:1:23 | Function generator_func | generator.py:2:24:2:25 | ControlFlowNode for xs |
|
||||
| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | ControlFlowNode for .0 |
|
||||
| generator.py:2:12:2:26 | Function listcomp | generator.py:2:12:2:26 | ControlFlowNode for .0 |
|
||||
| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | ControlFlowNode for Yield |
|
||||
| generator.py:2:12:2:26 | Function listcomp | generator.py:2:13:2:13 | ControlFlowNode for x |
|
||||
| generator.py:2:12:2:26 | Function listcomp | generator.py:2:19:2:19 | ControlFlowNode for x |
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
testFailures
|
||||
| test.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
|
||||
| test.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
|
||||
| test_dict.py:4:17:4:60 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
|
||||
| test_dict.py:4:33:4:59 | ControlFlowNode for Attribute() | Unexpected result: unresolved_call=os.path.dirname(..) |
|
||||
failures
|
||||
|
||||
@@ -23,3 +23,4 @@
|
||||
| test.py:195:9:195:14 | ControlFlowNode for SOURCE | test.py:199:14:199:14 | ControlFlowNode for t |
|
||||
| test.py:202:10:202:15 | ControlFlowNode for SOURCE | test.py:204:14:204:14 | ControlFlowNode for i |
|
||||
| test.py:202:10:202:15 | ControlFlowNode for SOURCE | test.py:205:10:205:10 | ControlFlowNode for i |
|
||||
| test.py:208:12:208:17 | ControlFlowNode for SOURCE | test.py:214:14:214:14 | ControlFlowNode for x |
|
||||
|
||||
@@ -211,4 +211,4 @@ def flow_in_generator():
|
||||
|
||||
def flow_from_generator():
|
||||
for x in flow_in_generator():
|
||||
SINK(x) # Flow not found
|
||||
SINK(x)
|
||||
|
||||
@@ -61,7 +61,7 @@ def test_access(x, y, z):
|
||||
iter(tainted_list), # $ tainted
|
||||
next(iter(tainted_list)), # $ MISSING: tainted
|
||||
[i for i in tainted_list], # $ tainted
|
||||
[tainted_list for _i in [1,2,3]], # $ MISSING: tainted
|
||||
[tainted_list for _i in [1,2,3]], # $ tainted
|
||||
)
|
||||
|
||||
a, b, c = tainted_list[0:3]
|
||||
@@ -85,7 +85,7 @@ def test_access_explicit(x, y, z):
|
||||
iter(tainted_list), # $ tainted
|
||||
next(iter(tainted_list)), # $ tainted
|
||||
[i for i in tainted_list], # $ tainted
|
||||
[tainted_list for i in [1,2,3]], # $ MISSING: tainted
|
||||
[tainted_list for i in [1,2,3]], # $ tainted
|
||||
[TAINTED_STRING for i in [1,2,3]], # $ tainted
|
||||
[tainted_list], # $ tainted
|
||||
)
|
||||
|
||||
@@ -43,3 +43,12 @@ class MyLogger(logging.Logger):
|
||||
pass
|
||||
|
||||
MyLogger("bar").info("hello") # $ loggingInput="hello"
|
||||
|
||||
class CustomLogger(logging.getLoggerClass()):
|
||||
pass
|
||||
|
||||
CustomLogger("baz").info("hello") # $ loggingInput="hello"
|
||||
|
||||
class LoggerSubClassUsingSelf(logging.Logger):
|
||||
def foo(self):
|
||||
self.info("hello") # $ loggingInput="hello"
|
||||
@@ -30,7 +30,7 @@ def test_cgi_FieldStorage_taint():
|
||||
form['key'][0].value, # $ tainted
|
||||
form['key'][0].file, # $ tainted
|
||||
form['key'][0].filename, # $ tainted
|
||||
[field.value for field in form['key']], # $ MISSING: tainted
|
||||
[field.value for field in form['key']], # $ tainted
|
||||
|
||||
# `form.getvalue('key')` will be a list, if multiple fields named "key" are provided
|
||||
form.getvalue('key'), # $ tainted
|
||||
@@ -40,7 +40,7 @@ def test_cgi_FieldStorage_taint():
|
||||
|
||||
form.getlist('key'), # $ tainted
|
||||
form.getlist('key')[0], # $ tainted
|
||||
[field.value for field in form.getlist('key')], # $ MISSING: tainted
|
||||
[field.value for field in form.getlist('key')], # $ tainted
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -38,6 +38,12 @@ ensure_tainted(
|
||||
|
||||
compiled_pat.match(ts).string, # $ tainted
|
||||
re.compile(ts).match("safe").re.pattern, # $ tainted
|
||||
|
||||
list(re.finditer(pat, ts))[0].string, # $ tainted
|
||||
[m.string for m in re.finditer(pat, ts)], # $ tainted
|
||||
|
||||
list(re.finditer(pat, ts))[0].groups()[0], # $ MISSING: tainted // this requires list content in type tracking
|
||||
[m.groups()[0] for m in re.finditer(pat, ts)], # $ tainted
|
||||
)
|
||||
ensure_not_tainted(
|
||||
safe_match.expand("Hello \1"),
|
||||
|
||||
@@ -37,7 +37,7 @@ explicit_argv_parsing = parser.parse_args(sys.argv) # $ threatModelSource[comman
|
||||
ensure_tainted(explicit_argv_parsing.foo) # $ tainted
|
||||
|
||||
fake_args = parser.parse_args(["<foo>"])
|
||||
ensure_not_tainted(fake_args.foo) # $ SPURIOUS: tainted
|
||||
ensure_not_tainted(fake_args.foo)
|
||||
|
||||
########################################
|
||||
# reading input from stdin
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||
testFailures
|
||||
failures
|
||||
@@ -0,0 +1,2 @@
|
||||
import experimental.meta.InlineTaintTest
|
||||
import MakeInlineTaintTest<TestTaintTrackingConfig>
|
||||
10
python/ql/test/library-tests/frameworks/urllib/taint_test.py
Normal file
10
python/ql/test/library-tests/frameworks/urllib/taint_test.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import urllib.parse
|
||||
|
||||
def test():
|
||||
ts = TAINTED_STRING
|
||||
|
||||
params = urllib.parse.parse_qs(ts)
|
||||
|
||||
ensure_tainted(
|
||||
params, # $ tainted
|
||||
)
|
||||
@@ -1,3 +1 @@
|
||||
| sqlite3 | 2 | 1 |
|
||||
| sqlite3.__init__ | 2 | 1 |
|
||||
| sqlite3.dump | 2 | 1 |
|
||||
|
||||
@@ -46,7 +46,7 @@ tar.extractall(members=tar)
|
||||
#Sanitize members
|
||||
def safemembers(members):
|
||||
for info in members:
|
||||
if badpath(info):
|
||||
if os.path.isabs(info.name) or ".." in info.name:
|
||||
raise
|
||||
yield info
|
||||
|
||||
|
||||
@@ -2,6 +2,5 @@
|
||||
| test.py:8:1:8:20 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
|
||||
| test.py:9:1:9:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to world writable. |
|
||||
| test.py:11:1:11:21 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group readable. |
|
||||
| test.py:13:1:13:28 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
|
||||
| test.py:14:1:14:19 | ControlFlowNode for Attribute() | Overly permissive mask in chmod sets file to group writable. |
|
||||
| test.py:16:1:16:25 | ControlFlowNode for Attribute() | Overly permissive mask in open sets file to world readable. |
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
| assert_raises.py:9:13:9:19 | ExprStmt | This statement has no effect. |
|
||||
| assert_raises.py:11:13:11:16 | ExprStmt | This statement has no effect. |
|
||||
| test.py:24:1:24:3 | ExprStmt | This statement has no effect. |
|
||||
| test.py:25:1:25:13 | ExprStmt | This statement has no effect. |
|
||||
| test.py:26:1:26:6 | ExprStmt | This statement has no effect. |
|
||||
|
||||
Reference in New Issue
Block a user