mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Python: Add small api enhancements
determined useful during documentation work.
This commit is contained in:
@@ -6,6 +6,7 @@ private import python
|
||||
private import DataFlowPrivate
|
||||
import semmle.python.dataflow.new.TypeTracker
|
||||
import Attributes
|
||||
import LocalSources
|
||||
private import semmle.python.essa.SsaCompute
|
||||
|
||||
/**
|
||||
@@ -138,6 +139,11 @@ class Node extends TNode {
|
||||
* Gets a local source node from which data may flow to this node in zero or more local steps.
|
||||
*/
|
||||
LocalSourceNode getALocalSource() { result.flowsTo(this) }
|
||||
|
||||
/**
|
||||
* Gets a local source node from which data may flow to this node in zero or more local steps.
|
||||
*/
|
||||
LocalSourceNode getALocalTaintSource() { result.taintFlowsTo(this) }
|
||||
}
|
||||
|
||||
/** A data-flow node corresponding to an SSA variable. */
|
||||
@@ -215,7 +221,7 @@ ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e }
|
||||
* The value of a parameter at function entry, viewed as a node in a data
|
||||
* flow graph.
|
||||
*/
|
||||
class ParameterNode extends CfgNode {
|
||||
class ParameterNode extends CfgNode, LocalSourceNode {
|
||||
ParameterDefinition def;
|
||||
|
||||
ParameterNode() {
|
||||
@@ -237,6 +243,9 @@ class ParameterNode extends CfgNode {
|
||||
Parameter getParameter() { result = def.getParameter() }
|
||||
}
|
||||
|
||||
/** Gets a node corresponding to parameter `p`. */
|
||||
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
|
||||
|
||||
/** A data flow node that represents a call argument. */
|
||||
class ArgumentNode extends Node {
|
||||
ArgumentNode() { this = any(DataFlowCall c).getArg(_) }
|
||||
@@ -467,103 +476,6 @@ class BarrierGuard extends GuardNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow node that is a source of local flow. This includes things like
|
||||
* - Expressions
|
||||
* - Function parameters
|
||||
*/
|
||||
class LocalSourceNode extends Node {
|
||||
LocalSourceNode() {
|
||||
not simpleLocalFlowStep+(any(CfgNode n), this) and
|
||||
not this instanceof ModuleVariableNode
|
||||
or
|
||||
this = any(ModuleVariableNode mvn).getARead()
|
||||
}
|
||||
|
||||
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
|
||||
pragma[inline]
|
||||
predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) }
|
||||
|
||||
/**
|
||||
* Gets a reference (read or write) of attribute `attrName` on this node.
|
||||
*/
|
||||
AttrRef getAnAttributeReference(string attrName) { Cached::namedAttrRef(this, attrName, result) }
|
||||
|
||||
/**
|
||||
* Gets a read of attribute `attrName` on this node.
|
||||
*/
|
||||
AttrRead getAnAttributeRead(string attrName) { result = getAnAttributeReference(attrName) }
|
||||
|
||||
/**
|
||||
* Gets a reference (read or write) of any attribute on this node.
|
||||
*/
|
||||
AttrRef getAnAttributeReference() {
|
||||
Cached::namedAttrRef(this, _, result)
|
||||
or
|
||||
Cached::dynamicAttrRef(this, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a read of any attribute on this node.
|
||||
*/
|
||||
AttrRead getAnAttributeRead() { result = getAnAttributeReference() }
|
||||
|
||||
/**
|
||||
* Gets a call to this node.
|
||||
*/
|
||||
CallCfgNode getACall() { Cached::call(this, result) }
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if `source` is a `LocalSourceNode` that can reach `sink` via local flow steps.
|
||||
*
|
||||
* The slightly backwards parametering ordering is to force correct indexing.
|
||||
*/
|
||||
cached
|
||||
predicate hasLocalSource(Node sink, Node source) {
|
||||
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
|
||||
// recursive case, so instead we check it explicitly here.
|
||||
source = sink and
|
||||
source instanceof LocalSourceNode
|
||||
or
|
||||
exists(Node mid |
|
||||
hasLocalSource(mid, source) and
|
||||
simpleLocalFlowStep(mid, sink)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `base` flows to the base of `ref` and `ref` has attribute name `attr`.
|
||||
*/
|
||||
cached
|
||||
predicate namedAttrRef(LocalSourceNode base, string attr, AttrRef ref) {
|
||||
base.flowsTo(ref.getObject()) and
|
||||
ref.getAttributeName() = attr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `base` flows to the base of `ref` and `ref` has no known attribute name.
|
||||
*/
|
||||
cached
|
||||
predicate dynamicAttrRef(LocalSourceNode base, AttrRef ref) {
|
||||
base.flowsTo(ref.getObject()) and
|
||||
not exists(ref.getAttributeName())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `func` flows to the callee of `call`.
|
||||
*/
|
||||
cached
|
||||
predicate call(LocalSourceNode func, CallCfgNode call) {
|
||||
exists(CfgNode n |
|
||||
func.flowsTo(n) and
|
||||
n = call.getFunction()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Algebraic datatype for tracking data content associated with values.
|
||||
* Content can be collection elements or object attributes.
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Provides support for intra-procedural tracking of a customizable
|
||||
* set of data flow nodes.
|
||||
*
|
||||
* Note that unlike `TypeTracker.qll`, this library only performs
|
||||
* local tracking within a function.
|
||||
*/
|
||||
|
||||
import python
|
||||
import DataFlowPublic
|
||||
private import DataFlowPrivate
|
||||
private import TaintTrackingPublic
|
||||
|
||||
/**
|
||||
* A data flow node that is a source of local flow. This includes things like
|
||||
* - Expressions
|
||||
* - Function parameters
|
||||
*/
|
||||
class LocalSourceNode extends Node {
|
||||
LocalSourceNode() {
|
||||
not simpleLocalFlowStep+(any(CfgNode n), this) and
|
||||
not this instanceof ModuleVariableNode
|
||||
or
|
||||
this = any(ModuleVariableNode mvn).getARead()
|
||||
}
|
||||
|
||||
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
|
||||
pragma[inline]
|
||||
predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) }
|
||||
|
||||
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local taint steps. */
|
||||
pragma[inline]
|
||||
predicate taintFlowsTo(Node nodeTo) { Cached::hasLocalTaintSource(nodeTo, this) }
|
||||
|
||||
/**
|
||||
* Gets a reference (read or write) of attribute `attrName` on this node.
|
||||
*/
|
||||
AttrRef getAnAttributeReference(string attrName) { Cached::namedAttrRef(this, attrName, result) }
|
||||
|
||||
/**
|
||||
* Gets a read of attribute `attrName` on this node.
|
||||
*/
|
||||
AttrRead getAnAttributeRead(string attrName) { result = getAnAttributeReference(attrName) }
|
||||
|
||||
/**
|
||||
* Gets a reference (read or write) of any attribute on this node.
|
||||
*/
|
||||
AttrRef getAnAttributeReference() {
|
||||
Cached::namedAttrRef(this, _, result)
|
||||
or
|
||||
Cached::dynamicAttrRef(this, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a read of any attribute on this node.
|
||||
*/
|
||||
AttrRead getAnAttributeRead() { result = getAnAttributeReference() }
|
||||
|
||||
/**
|
||||
* Gets a call to this node.
|
||||
*/
|
||||
CallCfgNode getACall() { Cached::call(this, result) }
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
/**
|
||||
* Holds if `source` is a `LocalSourceNode` that can reach `sink` via local flow steps.
|
||||
*
|
||||
* The slightly backwards parametering ordering is to force correct indexing.
|
||||
*/
|
||||
cached
|
||||
predicate hasLocalSource(Node sink, Node source) {
|
||||
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
|
||||
// recursive case, so instead we check it explicitly here.
|
||||
source = sink and
|
||||
source instanceof LocalSourceNode
|
||||
or
|
||||
exists(Node mid |
|
||||
hasLocalSource(mid, source) and
|
||||
simpleLocalFlowStep(mid, sink)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `source` is a `LocalSourceNode` that can reach `sink` via local taint steps.
|
||||
*
|
||||
* The slightly backwards parametering ordering is to force correct indexing.
|
||||
*/
|
||||
cached
|
||||
predicate hasLocalTaintSource(Node sink, Node source) {
|
||||
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
|
||||
// recursive case, so instead we check it explicitly here.
|
||||
source = sink and
|
||||
source instanceof LocalSourceNode
|
||||
or
|
||||
exists(Node mid |
|
||||
hasLocalTaintSource(mid, source) and
|
||||
localTaintStep(mid, sink)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `base` flows to the base of `ref` and `ref` has attribute name `attr`.
|
||||
*/
|
||||
cached
|
||||
predicate namedAttrRef(LocalSourceNode base, string attr, AttrRef ref) {
|
||||
base.flowsTo(ref.getObject()) and
|
||||
ref.getAttributeName() = attr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `base` flows to the base of `ref` and `ref` has no known attribute name.
|
||||
*/
|
||||
cached
|
||||
predicate dynamicAttrRef(LocalSourceNode base, AttrRef ref) {
|
||||
base.flowsTo(ref.getObject()) and
|
||||
not exists(ref.getAttributeName())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `func` flows to the callee of `call`.
|
||||
*/
|
||||
cached
|
||||
predicate call(LocalSourceNode func, CallCfgNode call) {
|
||||
exists(CfgNode n |
|
||||
func.flowsTo(n) and
|
||||
n = call.getFunction()
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user