Merge remote-tracking branch 'origin/main' into dbartol/mergeback-3.10

This commit is contained in:
Dave Bartolomeo
2023-07-06 10:00:46 -04:00
1654 changed files with 47750 additions and 21714 deletions

View File

@@ -3,3 +3,4 @@ groups: [python, test, consistency-queries]
dependencies:
codeql/python-all: ${workspace}
extractor: python
warnOnImplicitThis: true

View File

@@ -4,3 +4,4 @@ groups:
- examples
dependencies:
codeql/python-all: ${workspace}
warnOnImplicitThis: true

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Type tracking is now aware of flow summaries. This leads to a richer API graph, and may lead to more results in some queries.

View File

@@ -0,0 +1,9 @@
---
category: minorAnalysis
---
* Deleted many deprecated predicates and classes with uppercase `API`, `HTTP`, `XSS`, `SQL`, etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated `getName()` predicate from the `Container` class, use `getAbsolutePath()` instead.
* Deleted many deprecated module names that started with a lowercase letter, use the versions that start with an uppercase letter instead.
* Deleted many deprecated predicates in `PointsTo.qll`.
* Deleted many deprecated files from the `semmle.python.security` package.
* Deleted the deprecated `BottleRoutePointToExtension` class from `Extensions.qll`.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added modeling of taint flow through the template argument of `flask.render_template_string` and `flask.stream_template_string`.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* More precise modelling of several container functions (such as `sorted`, `reversed`) and methods (such as `set.add`, `list.append`).

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Deleted many models that used the old dataflow library, the new models can be found in the `python/ql/lib/semmle/python/frameworks` folder.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* It is now possible to specify flow summaries in the format "MyPkg;Member[list_map];Argument[1].ListElement;Argument[0].Parameter[0];value"

View File

@@ -6,6 +6,7 @@ extractor: python
library: true
upgrades: upgrades
dependencies:
codeql/mad: ${workspace}
codeql/regex: ${workspace}
codeql/tutorial: ${workspace}
codeql/util: ${workspace}

View File

@@ -154,12 +154,6 @@ abstract class Container extends @container {
*/
string toString() { result = this.getAbsolutePath() }
/**
* Gets the name of this container.
* DEPRECATED: Use `getAbsolutePath` instead.
*/
deprecated string getName() { result = this.getAbsolutePath() }
/**
* Gets the relative path of this file or folder from the root folder of the
* analyzed source location. The relative path of the root folder itself is

View File

@@ -90,39 +90,32 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari
}
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
// // This gives access to getNodeFromPath, which is not constrained to `CallNode`s
// // as `resolvedSummaryBase` is.
// private import semmle.python.frameworks.data.internal.ApiGraphModels as AGM
//
// private class SummarizedCallableFromModel extends SummarizedCallable {
// string package;
// string type;
// string path;
// SummarizedCallableFromModel() {
// ModelOutput::relevantSummaryModel(package, type, path, _, _, _) and
// this = package + ";" + type + ";" + path
// }
// override CallCfgNode getACall() {
// exists(API::CallNode base |
// ModelOutput::resolvedSummaryBase(package, type, path, base) and
// result = base.getACall()
// )
// }
// override ArgumentNode getACallback() {
// exists(API::Node base |
// base = AGM::getNodeFromPath(package, type, path) and
// result = base.getAValueReachableFromSource()
// )
// }
// override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
// exists(string kind |
// ModelOutput::relevantSummaryModel(package, type, path, input, output, kind)
// |
// kind = "value" and
// preservesValue = true
// or
// kind = "taint" and
// preservesValue = false
// )
// }
// }
private class SummarizedCallableFromModel extends SummarizedCallable {
string type;
string path;
SummarizedCallableFromModel() {
ModelOutput::relevantSummaryModel(type, path, _, _, _) and
this = type + ";" + path
}
override CallCfgNode getACall() { ModelOutput::resolvedSummaryBase(type, path, result) }
override ArgumentNode getACallback() {
exists(API::Node base |
ModelOutput::resolvedSummaryRefBase(type, path, base) and
result = base.getAValueReachableFromSource()
)
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
exists(string kind | ModelOutput::relevantSummaryModel(type, path, input, output, kind) |
kind = "value" and
preservesValue = true
or
kind = "taint" and
preservesValue = false
)
}
}

View File

@@ -251,6 +251,9 @@ abstract class LibraryCallable extends string {
/** Gets a call to this library callable. */
abstract CallCfgNode getACall();
/** Same as `getACall` but without referring to the call graph or API graph. */
CallCfgNode getACallSimple() { none() }
/** Gets a data-flow node, where this library callable is used as a call-back. */
abstract ArgumentNode getACallback();
}
@@ -1224,7 +1227,6 @@ predicate normalCallArg(CallNode call, Node arg, ArgumentPosition apos) {
* time the bound method is used, such that the `clear()` call would essentially be
* translated into `l.clear()`, and we can still have use-use flow.
*/
pragma[assume_small_delta]
cached
predicate getCallArg(CallNode call, Function target, CallType type, Node arg, ArgumentPosition apos) {
Stages::DataFlow::ref() and
@@ -1316,7 +1318,9 @@ newtype TDataFlowCall =
TNormalCall(CallNode call, Function target, CallType type) { resolveCall(call, target, type) } or
TPotentialLibraryCall(CallNode call) or
/** A synthesized call inside a summarized callable */
TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, Node receiver) {
TSummaryCall(
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
@@ -1448,12 +1452,12 @@ class PotentialLibraryCall extends ExtractedDataFlowCall, TPotentialLibraryCall
*/
class SummaryCall extends DataFlowCall, TSummaryCall {
private FlowSummaryImpl::Public::SummarizedCallable c;
private Node receiver;
private FlowSummaryImpl::Private::SummaryNode receiver;
SummaryCall() { this = TSummaryCall(c, receiver) }
/** Gets the data flow node that this call targets. */
Node getReceiver() { result = receiver }
FlowSummaryImpl::Private::SummaryNode getReceiver() { result = receiver }
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c }
@@ -1486,44 +1490,35 @@ abstract class ParameterNodeImpl extends Node {
}
/** A parameter for a library callable with a flow summary. */
class SummaryParameterNode extends ParameterNodeImpl, TSummaryParameterNode {
private FlowSummaryImpl::Public::SummarizedCallable sc;
private ParameterPosition pos;
class SummaryParameterNode extends ParameterNodeImpl, FlowSummaryNode {
SummaryParameterNode() {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _)
}
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos) }
private ParameterPosition getPosition() {
FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result)
}
override Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition ppos) {
sc = c.asLibraryCallable() and ppos = pos
}
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = sc }
override string toString() { result = "parameter " + pos + " of " + sc }
// Hack to return "empty location"
override predicate hasLocationInfo(
string file, int startline, int startcolumn, int endline, int endcolumn
) {
file = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
this.getSummarizedCallable() = c.asLibraryCallable() and ppos = this.getPosition()
}
}
/** A data-flow node used to model flow summaries. */
class SummaryNode extends Node, TSummaryNode {
private FlowSummaryImpl::Public::SummarizedCallable c;
private FlowSummaryImpl::Private::SummaryNodeState state;
class FlowSummaryNode extends Node, TFlowSummaryNode {
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
SummaryNode() { this = TSummaryNode(c, state) }
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
result = this.getSummaryNode().getSummarizedCallable()
}
override DataFlowCallable getEnclosingCallable() { result.asLibraryCallable() = c }
override DataFlowCallable getEnclosingCallable() {
result.asLibraryCallable() = this.getSummarizedCallable()
}
override string toString() { result = "[summary] " + state + " in " + c }
override string toString() { result = this.getSummaryNode().toString() }
// Hack to return "empty location"
override predicate hasLocationInfo(
@@ -1537,26 +1532,30 @@ class SummaryNode extends Node, TSummaryNode {
}
}
private class SummaryReturnNode extends SummaryNode, ReturnNode {
private class SummaryReturnNode extends FlowSummaryNode, ReturnNode {
private ReturnKind rk;
SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this, rk) }
SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this.getSummaryNode(), rk) }
override ReturnKind getKind() { result = rk }
}
private class SummaryArgumentNode extends SummaryNode, ArgumentNode {
SummaryArgumentNode() { FlowSummaryImpl::Private::summaryArgumentNode(_, this, _) }
private class SummaryArgumentNode extends FlowSummaryNode, ArgumentNode {
SummaryArgumentNode() {
FlowSummaryImpl::Private::summaryArgumentNode(_, this.getSummaryNode(), _)
}
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos)
FlowSummaryImpl::Private::summaryArgumentNode(call, this.getSummaryNode(), pos)
}
}
private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNodeImpl {
private Node pre;
private class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNodeImpl {
private FlowSummaryNode pre;
SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, pre) }
SummaryPostUpdateNode() {
FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(), pre.getSummaryNode())
}
override Node getPreUpdateNode() { result = pre }
}
@@ -1625,11 +1624,11 @@ private module OutNodes {
}
}
private class SummaryOutNode extends SummaryNode, OutNode {
SummaryOutNode() { FlowSummaryImpl::Private::summaryOutNode(_, this, _) }
private class SummaryOutNode extends FlowSummaryNode, OutNode {
SummaryOutNode() { FlowSummaryImpl::Private::summaryOutNode(_, this.getSummaryNode(), _) }
override DataFlowCall getCall(ReturnKind kind) {
FlowSummaryImpl::Private::summaryOutNode(result, this, kind)
FlowSummaryImpl::Private::summaryOutNode(result, this.getSummaryNode(), kind)
}
}
}

View File

@@ -460,7 +460,6 @@ module Impl<FullStateConfigSig Config> {
* The Boolean `cc` records whether the node is reached through an
* argument in a call.
*/
pragma[assume_small_delta]
private predicate fwdFlow(NodeEx node, Cc cc) {
sourceNode(node, _) and
if hasSourceCallCtx() then cc = true else cc = false
@@ -570,7 +569,6 @@ module Impl<FullStateConfigSig Config> {
/**
* Holds if `c` is the target of a store in the flow covered by `fwdFlow`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate fwdFlowConsCand(Content c) {
exists(NodeEx mid, NodeEx node |
@@ -1135,8 +1133,8 @@ module Impl<FullStateConfigSig Config> {
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
);
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
bindingset[typ, contentType]
predicate typecheckStore(Typ typ, DataFlowType contentType);
@@ -1199,20 +1197,23 @@ module Impl<FullStateConfigSig Config> {
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap, ApApprox apa
) {
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
PrevStage::revFlow(node, state, apa) and
filter(node, state, t, ap)
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
}
pragma[inline]
additional predicate fwdFlow(
private predicate fwdFlow1(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
) {
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
PrevStage::revFlow(node, state, apa) and
filter(node, state, t0, ap, t)
}
pragma[nomagic]
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
}
pragma[assume_small_delta]
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
@@ -1339,6 +1340,11 @@ module Impl<FullStateConfigSig Config> {
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
cons = apCons(c, t1, tail)
or
exists(Typ t0 |
typeStrengthen(t0, cons, t2) and
fwdFlowConsCand(t0, cons, c, t1, tail)
)
}
pragma[nomagic]
@@ -1359,7 +1365,7 @@ module Impl<FullStateConfigSig Config> {
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
) {
exists(ApHeadContent apc |
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
apc = getHeadContent(ap) and
readStepCand0(node1, apc, c, node2)
)
@@ -1520,14 +1526,14 @@ module Impl<FullStateConfigSig Config> {
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
) {
revFlow0(node, state, returnCtx, returnAp, ap) and
fwdFlow(node, state, _, _, _, _, _, ap)
fwdFlow(node, state, _, _, _, _, _, ap, _)
}
pragma[nomagic]
private predicate revFlow0(
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
) {
fwdFlow(node, state, _, _, _, _, _, ap) and
fwdFlow(node, state, _, _, _, _, _, ap, _) and
sinkNode(node, state) and
(
if hasSinkCallCtx()
@@ -1780,13 +1786,13 @@ module Impl<FullStateConfigSig Config> {
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
) {
fwd = true and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
@@ -1963,10 +1969,10 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
PrevStage::revFlowState(state) and
exists(t) and
t0 = t and
exists(ap) and
not stateBarrier(node, state) and
(
@@ -2012,7 +2018,8 @@ module Impl<FullStateConfigSig Config> {
FlowCheckNode() {
castNode(this.asNode()) or
clearsContentCached(this.asNode(), _) or
expectsContentCached(this.asNode(), _)
expectsContentCached(this.asNode(), _) or
neverSkipInPathGraph(this.asNode())
}
}
@@ -2197,8 +2204,8 @@ module Impl<FullStateConfigSig Config> {
import BooleanCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
exists(lcc)
@@ -2218,10 +2225,16 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
exists(state) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
// We can get away with not using type strengthening here, since we aren't
// going to use the tracked types in the construction of Stage 4 access
// paths. For Stage 4 and onwards, the tracked types must be consistent as
// the cons candidates including types are used to construct subsequent
// access path approximations.
t0 = t and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
(
notExpectsContent(node)
or
@@ -2241,6 +2254,16 @@ module Impl<FullStateConfigSig Config> {
import MkStage<Stage2>::Stage<Stage3Param>
}
bindingset[node, t0]
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
if castingNodeEx(node)
then
exists(DataFlowType nt | nt = node.getDataFlowType() |
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
)
else t = t0
}
private module Stage4Param implements MkStage<Stage3>::StageParam {
private module PrevStage = Stage3;
@@ -2274,8 +2297,8 @@ module Impl<FullStateConfigSig Config> {
pragma[nomagic]
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
@@ -2333,11 +2356,11 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
exists(state) and
not clear(node, ap) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
strengthenType(node, t0, t) and
(
notExpectsContent(node)
or
@@ -2365,7 +2388,7 @@ module Impl<FullStateConfigSig Config> {
exists(AccessPathFront apf |
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
apf)
apf, _)
)
}
@@ -2579,8 +2602,8 @@ module Impl<FullStateConfigSig Config> {
import LocalCallContext
predicate localStep(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, LocalCc lcc
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
LocalCc lcc
) {
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
@@ -2609,9 +2632,9 @@ module Impl<FullStateConfigSig Config> {
)
}
bindingset[node, state, t, ap]
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
bindingset[node, state, t0, ap]
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
strengthenType(node, t0, t) and
exists(state) and
exists(ap)
}
@@ -2632,7 +2655,7 @@ module Impl<FullStateConfigSig Config> {
Stage5::parameterMayFlowThrough(p, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
TAccessPathApproxSome(apa), _, apa0)
TAccessPathApproxSome(apa), _, apa0, _)
)
}
@@ -2649,7 +2672,7 @@ module Impl<FullStateConfigSig Config> {
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
exists(AccessPathApprox apa | ap.getApprox() = apa |
Stage5::parameterMayFlowThrough(p, apa) and
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
Stage5::revFlow(p, state, _)
)
}
@@ -2751,7 +2774,6 @@ module Impl<FullStateConfigSig Config> {
/**
* Gets the number of `AccessPath`s that correspond to `apa`.
*/
pragma[assume_small_delta]
private int countAps(AccessPathApprox apa) {
evalUnfold(apa, false) and
result = 1 and
@@ -2770,7 +2792,6 @@ module Impl<FullStateConfigSig Config> {
* that it is expanded to a precise head-tail representation.
*/
language[monotonicAggregates]
pragma[assume_small_delta]
private int countPotentialAps(AccessPathApprox apa) {
apa instanceof AccessPathApproxNil and result = 1
or
@@ -2807,7 +2828,6 @@ module Impl<FullStateConfigSig Config> {
}
private newtype TPathNode =
pragma[assume_small_delta]
TPathNodeMid(
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap
) {
@@ -2820,9 +2840,7 @@ module Impl<FullStateConfigSig Config> {
ap = TAccessPathNil()
or
// ... or a step from an existing PathNode to another node.
pathStep(_, node, state, cc, sc, t, ap) and
Stage5::revFlow(node, state, ap.getApprox()) and
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
pathStep(_, node, state, cc, sc, t, ap)
} or
TPathNodeSink(NodeEx node, FlowState state) {
exists(PathNodeMid sink |
@@ -2894,7 +2912,6 @@ module Impl<FullStateConfigSig Config> {
override AccessPathFrontHead getFront() { result = TFrontHead(head_) }
pragma[assume_small_delta]
override AccessPathApproxCons getApprox() {
result = TConsNil(head_, t) and tail_ = TAccessPathNil()
or
@@ -2903,7 +2920,6 @@ module Impl<FullStateConfigSig Config> {
result = TCons1(head_, this.length())
}
pragma[assume_small_delta]
override int length() { result = 1 + tail_.length() }
private string toStringImpl(boolean needsSuffix) {
@@ -3340,13 +3356,23 @@ module Impl<FullStateConfigSig Config> {
ap = mid.getAp()
}
private predicate pathStep(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
AccessPath ap
) {
exists(DataFlowType t0 |
pathStep0(mid, node, state, cc, sc, t0, ap) and
Stage5::revFlow(node, state, ap.getApprox()) and
strengthenType(node, t0, t)
)
}
/**
* Holds if data may flow from `mid` to `node`. The last step in or out of
* a callable is recorded by `cc`.
*/
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathStep(
private predicate pathStep0(
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
AccessPath ap
) {
@@ -3557,7 +3583,6 @@ module Impl<FullStateConfigSig Config> {
)
}
pragma[assume_small_delta]
pragma[nomagic]
private predicate pathThroughCallable0(
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, FlowState state, CallContext cc,
@@ -3964,7 +3989,7 @@ module Impl<FullStateConfigSig Config> {
ap = TPartialNil() and
exists(explorationLimit())
or
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
distSrc(node.getEnclosingCallable()) <= explorationLimit()
} or
TPartialPathNodeRev(
@@ -3990,11 +4015,20 @@ module Impl<FullStateConfigSig Config> {
}
pragma[nomagic]
private predicate partialPathNodeMk0(
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
private predicate partialPathStep(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
) {
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
}
pragma[nomagic]
private predicate partialPathStep1(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
PartialAccessPath ap
) {
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
not fullBarrier(node) and
not stateBarrier(node, state) and
not clearsContentEx(node, ap.getHead()) and
@@ -4002,9 +4036,14 @@ module Impl<FullStateConfigSig Config> {
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), t)
else any()
strengthenType(node, t0, t)
}
pragma[nomagic]
private predicate partialPathTypeStrengthen(
DataFlowType t0, PartialAccessPath ap, DataFlowType t
) {
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
}
/**
@@ -4183,7 +4222,8 @@ module Impl<FullStateConfigSig Config> {
}
}
private predicate partialPathStep(
pragma[nomagic]
private predicate partialPathStep0(
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
) {
@@ -4309,6 +4349,11 @@ module Impl<FullStateConfigSig Config> {
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
) {
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
or
exists(DataFlowType t0 |
partialPathTypeStrengthen(t0, ap2, t2) and
apConsFwd(t1, ap1, c, t0, ap2)
)
}
pragma[nomagic]

View File

@@ -187,7 +187,6 @@ private module LambdaFlow {
else any()
}
pragma[assume_small_delta]
pragma[nomagic]
predicate revLambdaFlow0(
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
@@ -274,7 +273,6 @@ private module LambdaFlow {
)
}
pragma[assume_small_delta]
pragma[nomagic]
predicate revLambdaFlowOut(
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,

View File

@@ -441,14 +441,16 @@ predicate importTimeSummaryFlowStep(Node nodeFrom, Node nodeTo) {
// This will miss statements inside functions called from the top level.
isTopLevel(nodeFrom) and
isTopLevel(nodeTo) and
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true)
}
predicate runtimeSummaryFlowStep(Node nodeFrom, Node nodeTo) {
// Anything not at the top level can be executed at runtime.
not isTopLevel(nodeFrom) and
not isTopLevel(nodeTo) and
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true)
}
/** `ModuleVariable`s are accessed via jump steps at runtime. */
@@ -484,6 +486,14 @@ class DataFlowType extends TDataFlowType {
/** A node that performs a type cast. */
class CastNode extends Node {
CastNode() { none() }
}
/**
* Holds if `n` should never be skipped over in the `PathGraph` and in path
* explanations.
*/
predicate neverSkipInPathGraph(Node n) {
// We include read- and store steps here to force them to be
// shown in path explanations.
// This hack is necessary, because we have included some of these
@@ -492,7 +502,7 @@ class CastNode extends Node {
// We should revert this once, we can remove this steps from the
// default taint steps; this should be possible once we have
// implemented flow summaries and recursive content.
CastNode() { readStep(_, _, this) or storeStep(_, _, this) }
readStep(_, _, n) or storeStep(_, _, n)
}
/**
@@ -502,6 +512,8 @@ class CastNode extends Node {
pragma[inline]
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() }
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
/**
* Gets the type of `node`.
*/
@@ -527,7 +539,8 @@ predicate jumpStep(Node nodeFrom, Node nodeTo) {
or
jumpStepNotSharedWithTypeTracker(nodeFrom, nodeTo)
or
FlowSummaryImpl::Private::Steps::summaryJumpStep(nodeFrom, nodeTo)
FlowSummaryImpl::Private::Steps::summaryJumpStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode())
}
/**
@@ -600,7 +613,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
or
any(Orm::AdditionalOrmSteps es).storeStep(nodeFrom, c, nodeTo)
or
FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom, c, nodeTo)
FlowSummaryImpl::Private::Steps::summaryStoreStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c,
nodeTo.(FlowSummaryNode).getSummaryNode())
or
synthStarArgsElementParameterNodeStoreStep(nodeFrom, c, nodeTo)
or
@@ -792,19 +806,16 @@ predicate defaultValueFlowStep(CfgNode nodeFrom, CfgNode nodeTo) {
predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
subscriptReadStep(nodeFrom, c, nodeTo)
or
dictReadStep(nodeFrom, c, nodeTo)
or
iterableUnpackingReadStep(nodeFrom, c, nodeTo)
or
matchReadStep(nodeFrom, c, nodeTo)
or
popReadStep(nodeFrom, c, nodeTo)
or
forReadStep(nodeFrom, c, nodeTo)
or
attributeReadStep(nodeFrom, c, nodeTo)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom, c, nodeTo)
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom.(FlowSummaryNode).getSummaryNode(), c,
nodeTo.(FlowSummaryNode).getSummaryNode())
or
synthDictSplatParameterNodeReadStep(nodeFrom, c, nodeTo)
}
@@ -832,51 +843,6 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
)
}
predicate dictReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
// see
// - https://docs.python.org/3.10/library/stdtypes.html#dict.get
// - https://docs.python.org/3.10/library/stdtypes.html#dict.setdefault
exists(MethodCallNode call |
call.calls(nodeFrom, ["get", "setdefault"]) and
call.getArg(0).asExpr().(StrConst).getText() = c.(DictionaryElementContent).getKey() and
nodeTo = call
)
}
/** Data flows from a sequence to a call to `pop` on the sequence. */
predicate popReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
// set.pop or list.pop
// `s.pop()`
// nodeFrom is `s`, cfg node
// nodeTo is `s.pop()`, cfg node
// c denotes element of list or set
exists(CallNode call, AttrNode a |
call.getFunction() = a and
a.getName() = "pop" and // Should match appropriate call since we tracked a sequence here.
not exists(call.getAnArg()) and
nodeFrom.getNode() = a.getObject() and
nodeTo.getNode() = call and
(
c instanceof ListElementContent
or
c instanceof SetElementContent
)
)
or
// dict.pop
// `d.pop("key")`
// nodeFrom is `d`, cfg node
// nodeTo is `d.pop("key")`, cfg node
// c denotes the key `"key"`
exists(CallNode call, AttrNode a |
call.getFunction() = a and
a.getName() = "pop" and // Should match appropriate call since we tracked a dictionary here.
nodeFrom.getNode() = a.getObject() and
nodeTo.getNode() = call and
c.(DictionaryElementContent).getKey() = call.getArg(0).getNode().(StrConst).getS()
)
}
predicate forReadStep(CfgNode nodeFrom, Content c, Node nodeTo) {
exists(ForTarget target |
nodeFrom.asExpr() = target.getSource() and
@@ -919,7 +885,7 @@ predicate clearsContent(Node n, Content c) {
or
dictClearStep(n, c)
or
FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c)
FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c)
or
dictSplatParameterNodeClearStep(n, c)
}
@@ -976,9 +942,7 @@ predicate forceHighPrecision(Content c) { none() }
predicate nodeIsHidden(Node n) {
n instanceof ModuleVariableNode
or
n instanceof SummaryNode
or
n instanceof SummaryParameterNode
n instanceof FlowSummaryNode
or
n instanceof SynthStarArgsElementParameterNode
or
@@ -1005,7 +969,7 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
receiver = call.(SummaryCall).getReceiver() and
receiver.(FlowSummaryNode).getSummaryNode() = call.(SummaryCall).getReceiver() and
exists(kind)
}

View File

@@ -105,14 +105,7 @@ newtype TNode =
// So for now we live with having these synthetic ORM nodes for _all_ classes, which
// is a bit wasteful, but we don't think it will hurt too much.
TSyntheticOrmModelNode(Class cls) or
TSummaryNode(
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state
) {
FlowSummaryImpl::Private::summaryNodeRange(c, state)
} or
TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) {
FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos)
} or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
/** A synthetic node to capture positional arguments that are passed to a `*args` parameter. */
TSynthStarArgsElementParameterNode(DataFlowCallable callable) {
exists(ParameterPosition ppos | ppos.isStarArgs(_) | exists(callable.getParameter(ppos)))

View File

@@ -23,29 +23,30 @@ module Public {
* content type, or a return kind.
*/
class SummaryComponent extends TSummaryComponent {
/** Gets a textual representation of this summary component. */
string toString() {
exists(ContentSet c | this = TContentSummaryComponent(c) and result = c.toString())
or
exists(ContentSet c | this = TWithoutContentSummaryComponent(c) and result = "without " + c)
or
exists(ContentSet c | this = TWithContentSummaryComponent(c) and result = "with " + c)
/** Gets a textual representation of this component used for MaD models. */
string getMadRepresentation() {
result = getMadRepresentationSpecific(this)
or
exists(ArgumentPosition pos |
this = TParameterSummaryComponent(pos) and result = "parameter " + pos
this = TParameterSummaryComponent(pos) and
result = "Parameter[" + getArgumentPosition(pos) + "]"
)
or
exists(ParameterPosition pos |
this = TArgumentSummaryComponent(pos) and result = "argument " + pos
this = TArgumentSummaryComponent(pos) and
result = "Argument[" + getParameterPosition(pos) + "]"
)
or
exists(ReturnKind rk | this = TReturnSummaryComponent(rk) and result = "return (" + rk + ")")
or
exists(SummaryComponent::SyntheticGlobal sg |
this = TSyntheticGlobalSummaryComponent(sg) and
result = "synthetic global (" + sg + ")"
exists(string synthetic |
this = TSyntheticGlobalSummaryComponent(synthetic) and
result = "SyntheticGlobal[" + synthetic + "]"
)
or
this = TReturnSummaryComponent(getReturnValueKind()) and result = "ReturnValue"
}
/** Gets a textual representation of this summary component. */
string toString() { result = this.getMadRepresentation() }
}
/** Provides predicates for constructing summary components. */
@@ -110,7 +111,6 @@ module Public {
}
/** Gets the stack obtained by dropping the first `i` elements, if any. */
pragma[assume_small_delta]
SummaryComponentStack drop(int i) {
i = 0 and result = this
or
@@ -125,19 +125,22 @@ module Public {
this = TSingletonSummaryComponentStack(result) or result = this.tail().bottom()
}
/** Gets a textual representation of this stack. */
string toString() {
/** Gets a textual representation of this stack used for MaD models. */
string getMadRepresentation() {
exists(SummaryComponent head, SummaryComponentStack tail |
head = this.head() and
tail = this.tail() and
result = tail + "." + head
result = tail.getMadRepresentation() + "." + head.getMadRepresentation()
)
or
exists(SummaryComponent c |
this = TSingletonSummaryComponentStack(c) and
result = c.toString()
result = c.getMadRepresentation()
)
}
/** Gets a textual representation of this stack. */
string toString() { result = this.getMadRepresentation() }
}
/** Provides predicates for constructing stacks of summary components. */
@@ -166,37 +169,6 @@ module Public {
SummaryComponentStack return(ReturnKind rk) { result = singleton(SummaryComponent::return(rk)) }
}
/** Gets a textual representation of this component used for flow summaries. */
private string getComponent(SummaryComponent sc) {
result = getComponentSpecific(sc)
or
exists(ArgumentPosition pos |
sc = TParameterSummaryComponent(pos) and
result = "Parameter[" + getArgumentPosition(pos) + "]"
)
or
exists(ParameterPosition pos |
sc = TArgumentSummaryComponent(pos) and
result = "Argument[" + getParameterPosition(pos) + "]"
)
or
sc = TReturnSummaryComponent(getReturnValueKind()) and result = "ReturnValue"
}
/** Gets a textual representation of this stack used for flow summaries. */
string getComponentStack(SummaryComponentStack stack) {
exists(SummaryComponent head, SummaryComponentStack tail |
head = stack.head() and
tail = stack.tail() and
result = getComponentStack(tail) + "." + getComponent(head)
)
or
exists(SummaryComponent c |
stack = TSingletonSummaryComponentStack(c) and
result = getComponent(c)
)
}
/**
* A class that exists for QL technical reasons only (the IPA type used
* to represent component stacks needs to be bounded).
@@ -505,6 +477,9 @@ module Private {
or
// Add the post-update node corresponding to the requested argument node
outputState(c, s) and isCallbackParameter(s)
or
// Add the parameter node for parameter side-effects
outputState(c, s) and s = SummaryComponentStack::argument(_)
}
private newtype TSummaryNodeState =
@@ -530,7 +505,7 @@ module Private {
* this state represents that the components in `s` _remain to be written_ to
* the output.
*/
class SummaryNodeState extends TSummaryNodeState {
private class SummaryNodeState extends TSummaryNodeState {
/** Holds if this state is a valid input state for `c`. */
pragma[nomagic]
predicate isInputState(SummarizedCallable c, SummaryComponentStack s) {
@@ -559,6 +534,42 @@ module Private {
}
}
private newtype TSummaryNode =
TSummaryInternalNode(SummarizedCallable c, SummaryNodeState state) {
summaryNodeRange(c, state)
} or
TSummaryParameterNode(SummarizedCallable c, ParameterPosition pos) {
summaryParameterNodeRange(c, pos)
}
abstract class SummaryNode extends TSummaryNode {
abstract string toString();
abstract SummarizedCallable getSummarizedCallable();
}
private class SummaryInternalNode extends SummaryNode, TSummaryInternalNode {
private SummarizedCallable c;
private SummaryNodeState state;
SummaryInternalNode() { this = TSummaryInternalNode(c, state) }
override string toString() { result = "[summary] " + state + " in " + c }
override SummarizedCallable getSummarizedCallable() { result = c }
}
private class SummaryParamNode extends SummaryNode, TSummaryParameterNode {
private SummarizedCallable c;
private ParameterPosition pos;
SummaryParamNode() { this = TSummaryParameterNode(c, pos) }
override string toString() { result = "[summary param] " + pos + " in " + c }
override SummarizedCallable getSummarizedCallable() { result = c }
}
/**
* Holds if `state` represents having read from a parameter at position
* `pos` in `c`. In this case we are not synthesizing a data-flow node,
@@ -574,7 +585,7 @@ module Private {
* Holds if a synthesized summary node is needed for the state `state` in summarized
* callable `c`.
*/
predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) {
private predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) {
state.isInputState(c, _) and
not parameterReadState(c, state, _)
or
@@ -582,22 +593,22 @@ module Private {
}
pragma[noinline]
private Node summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) {
private SummaryNode summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) {
exists(SummaryNodeState state | state.isInputState(c, s) |
result = summaryNode(c, state)
result = TSummaryInternalNode(c, state)
or
exists(ParameterPosition pos |
parameterReadState(c, state, pos) and
result.(ParamNode).isParameterOf(inject(c), pos)
result = TSummaryParameterNode(c, pos)
)
)
}
pragma[noinline]
private Node summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) {
private SummaryNode summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) {
exists(SummaryNodeState state |
state.isOutputState(c, s) and
result = summaryNode(c, state)
result = TSummaryInternalNode(c, state)
)
}
@@ -605,12 +616,14 @@ module Private {
* Holds if a write targets `post`, which is a post-update node for a
* parameter at position `pos` in `c`.
*/
private predicate isParameterPostUpdate(Node post, SummarizedCallable c, ParameterPosition pos) {
private predicate isParameterPostUpdate(
SummaryNode post, SummarizedCallable c, ParameterPosition pos
) {
post = summaryNodeOutputState(c, SummaryComponentStack::argument(pos))
}
/** Holds if a parameter node at position `pos` is required for `c`. */
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
private predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
parameterReadState(c, _, pos)
or
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
@@ -618,7 +631,7 @@ module Private {
}
private predicate callbackOutput(
SummarizedCallable c, SummaryComponentStack s, Node receiver, ReturnKind rk
SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ReturnKind rk
) {
any(SummaryNodeState state).isInputState(c, s) and
s.head() = TReturnSummaryComponent(rk) and
@@ -626,7 +639,7 @@ module Private {
}
private predicate callbackInput(
SummarizedCallable c, SummaryComponentStack s, Node receiver, ArgumentPosition pos
SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ArgumentPosition pos
) {
any(SummaryNodeState state).isOutputState(c, s) and
s.head() = TParameterSummaryComponent(pos) and
@@ -634,7 +647,7 @@ module Private {
}
/** Holds if a call targeting `receiver` should be synthesized inside `c`. */
predicate summaryCallbackRange(SummarizedCallable c, Node receiver) {
predicate summaryCallbackRange(SummarizedCallable c, SummaryNode receiver) {
callbackOutput(c, _, receiver, _)
or
callbackInput(c, _, receiver, _)
@@ -647,10 +660,10 @@ module Private {
* `getContentType()`, `getReturnType()`, `getCallbackParameterType()`, and
* `getCallbackReturnType()`.
*/
DataFlowType summaryNodeType(Node n) {
exists(Node pre |
DataFlowType summaryNodeType(SummaryNode n) {
exists(SummaryNode pre |
summaryPostUpdateNode(n, pre) and
result = getNodeType(pre)
result = summaryNodeType(pre)
)
or
exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | head = s.head() |
@@ -662,12 +675,12 @@ module Private {
)
or
head = TWithoutContentSummaryComponent(_) and
result = getNodeType(summaryNodeInputState(c, s.tail()))
result = summaryNodeType(summaryNodeInputState(c, s.tail()))
or
exists(ReturnKind rk |
head = TReturnSummaryComponent(rk) and
result =
getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
getCallbackReturnType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c),
s.tail())), rk)
)
or
@@ -675,6 +688,11 @@ module Private {
head = TSyntheticGlobalSummaryComponent(sg) and
result = getSyntheticGlobalType(sg)
)
or
exists(ParameterPosition pos |
head = TArgumentSummaryComponent(pos) and
result = getParameterType(c, pos)
)
)
or
n = summaryNodeOutputState(c, s) and
@@ -691,7 +709,7 @@ module Private {
or
exists(ArgumentPosition pos | head = TParameterSummaryComponent(pos) |
result =
getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c),
getCallbackParameterType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c),
s.tail())), pos)
)
or
@@ -703,9 +721,14 @@ module Private {
)
}
/** Holds if summary node `p` is a parameter with position `pos`. */
predicate summaryParameterNode(SummaryNode p, ParameterPosition pos) {
p = TSummaryParameterNode(_, pos)
}
/** Holds if summary node `out` contains output of kind `rk` from call `c`. */
predicate summaryOutNode(DataFlowCall c, Node out, ReturnKind rk) {
exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver |
predicate summaryOutNode(DataFlowCall c, SummaryNode out, ReturnKind rk) {
exists(SummarizedCallable callable, SummaryComponentStack s, SummaryNode receiver |
callbackOutput(callable, s, receiver, rk) and
out = summaryNodeInputState(callable, s) and
c = summaryDataFlowCall(receiver)
@@ -713,8 +736,8 @@ module Private {
}
/** Holds if summary node `arg` is at position `pos` in the call `c`. */
predicate summaryArgumentNode(DataFlowCall c, Node arg, ArgumentPosition pos) {
exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver |
predicate summaryArgumentNode(DataFlowCall c, SummaryNode arg, ArgumentPosition pos) {
exists(SummarizedCallable callable, SummaryComponentStack s, SummaryNode receiver |
callbackInput(callable, s, receiver, pos) and
arg = summaryNodeOutputState(callable, s) and
c = summaryDataFlowCall(receiver)
@@ -722,10 +745,10 @@ module Private {
}
/** Holds if summary node `post` is a post-update node with pre-update node `pre`. */
predicate summaryPostUpdateNode(Node post, Node pre) {
predicate summaryPostUpdateNode(SummaryNode post, SummaryNode pre) {
exists(SummarizedCallable c, ParameterPosition pos |
isParameterPostUpdate(post, c, pos) and
pre.(ParamNode).isParameterOf(inject(c), pos)
pre = TSummaryParameterNode(c, pos)
)
or
exists(SummarizedCallable callable, SummaryComponentStack s |
@@ -736,7 +759,7 @@ module Private {
}
/** Holds if summary node `ret` is a return node of kind `rk`. */
predicate summaryReturnNode(Node ret, ReturnKind rk) {
predicate summaryReturnNode(SummaryNode ret, ReturnKind rk) {
exists(SummaryComponentStack s |
ret = summaryNodeOutputState(_, s) and
s = TSingletonSummaryComponentStack(TReturnSummaryComponent(rk))
@@ -748,7 +771,9 @@ module Private {
* node, and back out to `p`.
*/
predicate summaryAllowParameterReturnInSelf(ParamNode p) {
exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(inject(c), ppos) |
exists(SummarizedCallable c, ParameterPosition ppos |
p.isParameterOf(inject(c), pragma[only_bind_into](ppos))
|
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
summary(c, inputContents, outputContents, _) and
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and
@@ -763,7 +788,7 @@ module Private {
* Holds if there is a local step from `pred` to `succ`, which is synthesized
* from a flow summary.
*/
predicate summaryLocalStep(Node pred, Node succ, boolean preservesValue) {
predicate summaryLocalStep(SummaryNode pred, SummaryNode succ, boolean preservesValue) {
exists(
SummarizedCallable c, SummaryComponentStack inputContents,
SummaryComponentStack outputContents
@@ -789,7 +814,7 @@ module Private {
* Holds if there is a read step of content `c` from `pred` to `succ`, which
* is synthesized from a flow summary.
*/
predicate summaryReadStep(Node pred, ContentSet c, Node succ) {
predicate summaryReadStep(SummaryNode pred, ContentSet c, SummaryNode succ) {
exists(SummarizedCallable sc, SummaryComponentStack s |
pred = summaryNodeInputState(sc, s.tail()) and
succ = summaryNodeInputState(sc, s) and
@@ -801,7 +826,7 @@ module Private {
* Holds if there is a store step of content `c` from `pred` to `succ`, which
* is synthesized from a flow summary.
*/
predicate summaryStoreStep(Node pred, ContentSet c, Node succ) {
predicate summaryStoreStep(SummaryNode pred, ContentSet c, SummaryNode succ) {
exists(SummarizedCallable sc, SummaryComponentStack s |
pred = summaryNodeOutputState(sc, s) and
succ = summaryNodeOutputState(sc, s.tail()) and
@@ -813,7 +838,7 @@ module Private {
* Holds if there is a jump step from `pred` to `succ`, which is synthesized
* from a flow summary.
*/
predicate summaryJumpStep(Node pred, Node succ) {
predicate summaryJumpStep(SummaryNode pred, SummaryNode succ) {
exists(SummaryComponentStack s |
s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and
pred = summaryNodeOutputState(_, s) and
@@ -840,9 +865,9 @@ module Private {
* `a` on line 2 to the post-update node for `a` on that line (via an intermediate
* node where field `b` is cleared).
*/
predicate summaryClearsContent(Node n, ContentSet c) {
predicate summaryClearsContent(SummaryNode n, ContentSet c) {
exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack |
n = summaryNode(sc, state) and
n = TSummaryInternalNode(sc, state) and
state.isInputState(sc, stack) and
stack.head() = SummaryComponent::withoutContent(c)
)
@@ -852,9 +877,9 @@ module Private {
* Holds if the value that is being tracked is expected to be stored inside
* content `c` at `n`.
*/
predicate summaryExpectsContent(Node n, ContentSet c) {
predicate summaryExpectsContent(SummaryNode n, ContentSet c) {
exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack |
n = summaryNode(sc, state) and
n = TSummaryInternalNode(sc, state) and
state.isInputState(sc, stack) and
stack.head() = SummaryComponent::withContent(c)
)
@@ -862,17 +887,17 @@ module Private {
pragma[noinline]
private predicate viableParam(
DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, ParamNode p
DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, SummaryParamNode p
) {
exists(DataFlowCallable c |
c = inject(sc) and
p.isParameterOf(c, ppos) and
p = TSummaryParameterNode(sc, ppos) and
c = viableCallable(call)
)
}
pragma[nomagic]
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg, SummarizedCallable sc) {
private SummaryParamNode summaryArgParam(DataFlowCall call, ArgNode arg, SummarizedCallable sc) {
exists(ParameterPosition ppos |
argumentPositionMatch(call, arg, ppos) and
viableParam(call, sc, ppos, result)
@@ -884,12 +909,12 @@ module Private {
* local steps. `clearsOrExpects` records whether any node on the path from `p` to
* `n` either clears or expects contents.
*/
private predicate paramReachesLocal(ParamNode p, Node n, boolean clearsOrExpects) {
private predicate paramReachesLocal(SummaryParamNode p, SummaryNode n, boolean clearsOrExpects) {
viableParam(_, _, _, p) and
n = p and
clearsOrExpects = false
or
exists(Node mid, boolean clearsOrExpectsMid |
exists(SummaryNode mid, boolean clearsOrExpectsMid |
paramReachesLocal(p, mid, clearsOrExpectsMid) and
summaryLocalStep(mid, n, true) and
if
@@ -909,21 +934,33 @@ module Private {
*/
pragma[nomagic]
predicate prohibitsUseUseFlow(ArgNode arg, SummarizedCallable sc) {
exists(ParamNode p, ParameterPosition ppos, Node ret |
exists(SummaryParamNode p, ParameterPosition ppos, SummaryNode ret |
paramReachesLocal(p, ret, true) and
p = summaryArgParam0(_, arg, sc) and
p.isParameterOf(_, pragma[only_bind_into](ppos)) and
p = summaryArgParam(_, arg, sc) and
p = TSummaryParameterNode(_, pragma[only_bind_into](ppos)) and
isParameterPostUpdate(ret, _, pragma[only_bind_into](ppos))
)
}
pragma[nomagic]
private predicate summaryReturnNodeExt(SummaryNode ret, ReturnKindExt rk) {
summaryReturnNode(ret, rk.(ValueReturnKind).getKind())
or
exists(SummaryParamNode p, SummaryNode pre, ParameterPosition pos |
paramReachesLocal(p, pre, _) and
summaryPostUpdateNode(ret, pre) and
p = TSummaryParameterNode(_, pos) and
rk.(ParamUpdateReturnKind).getPosition() = pos
)
}
bindingset[ret]
private ParamNode summaryArgParam(
ArgNode arg, ReturnNodeExt ret, OutNodeExt out, SummarizedCallable sc
private SummaryParamNode summaryArgParamRetOut(
ArgNode arg, SummaryNode ret, OutNodeExt out, SummarizedCallable sc
) {
exists(DataFlowCall call, ReturnKindExt rk |
result = summaryArgParam0(call, arg, sc) and
ret.getKind() = pragma[only_bind_into](rk) and
result = summaryArgParam(call, arg, sc) and
summaryReturnNodeExt(ret, pragma[only_bind_into](rk)) and
out = pragma[only_bind_into](rk).getAnOutNode(call)
)
}
@@ -936,9 +973,9 @@ module Private {
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) {
exists(ReturnKind rk, ReturnNode ret, DataFlowCall call |
summaryLocalStep(summaryArgParam0(call, arg, sc), ret, true) and
ret.getKind() = pragma[only_bind_into](rk) and
exists(ReturnKind rk, SummaryNode ret, DataFlowCall call |
summaryLocalStep(summaryArgParam(call, arg, sc), ret, true) and
summaryReturnNode(ret, pragma[only_bind_into](rk)) and
out = getAnOutNode(call, pragma[only_bind_into](rk))
)
}
@@ -951,7 +988,9 @@ module Private {
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) {
exists(ReturnNodeExt ret | summaryLocalStep(summaryArgParam(arg, ret, out, sc), ret, false))
exists(SummaryNode ret |
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, false)
)
}
/**
@@ -962,8 +1001,8 @@ module Private {
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
exists(Node mid, ReturnNodeExt ret |
summaryReadStep(summaryArgParam(arg, ret, out, sc), c, mid) and
exists(SummaryNode mid, SummaryNode ret |
summaryReadStep(summaryArgParamRetOut(arg, ret, out, sc), c, mid) and
summaryLocalStep(mid, ret, _)
)
}
@@ -976,8 +1015,8 @@ module Private {
* be useful to include in the exposed local data-flow/taint-tracking relations.
*/
predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) {
exists(Node mid, ReturnNodeExt ret |
summaryLocalStep(summaryArgParam(arg, ret, out, sc), mid, _) and
exists(SummaryNode mid, SummaryNode ret |
summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), mid, _) and
summaryStoreStep(mid, c, ret)
)
}
@@ -1310,8 +1349,8 @@ module Private {
c.relevantSummary(input, output, preservesValue) and
csv =
c.getCallableCsv() // Callable information
+ getComponentStack(input) + ";" // input
+ getComponentStack(output) + ";" // output
+ input.getMadRepresentation() + ";" // input
+ output.getMadRepresentation() + ";" // output
+ renderKind(preservesValue) + ";" // kind
+ renderProvenance(c) // provenance
)
@@ -1344,11 +1383,11 @@ module Private {
}
private newtype TNodeOrCall =
MkNode(Node n) {
MkNode(SummaryNode n) {
exists(RelevantSummarizedCallable c |
n = summaryNode(c, _)
n = TSummaryInternalNode(c, _)
or
n.(ParamNode).isParameterOf(inject(c), _)
n = TSummaryParameterNode(c, _)
)
} or
MkCall(DataFlowCall call) {
@@ -1357,7 +1396,7 @@ module Private {
}
private class NodeOrCall extends TNodeOrCall {
Node asNode() { this = MkNode(result) }
SummaryNode asNode() { this = MkNode(result) }
DataFlowCall asCall() { this = MkCall(result) }
@@ -1377,9 +1416,11 @@ module Private {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
or
this.asCall().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
filepath = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
}
}

View File

@@ -47,15 +47,15 @@ DataFlowCallable inject(SummarizedCallable c) { result.asLibraryCallable() = c }
/** Gets the parameter position of the instance parameter. */
ArgumentPosition callbackSelfParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
/** Gets the synthesized summary data-flow node for the given values. */
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
/** Gets the synthesized data-flow call for `receiver`. */
SummaryCall summaryDataFlowCall(Node receiver) { receiver = result.getReceiver() }
SummaryCall summaryDataFlowCall(SummaryNode receiver) { receiver = result.getReceiver() }
/** Gets the type of content `c`. */
DataFlowType getContentType(Content c) { any() }
/** Gets the type of the parameter at the given position. */
DataFlowType getParameterType(SummarizedCallable c, ParameterPosition pos) { any() }
/** Gets the return type of kind `rk` for callable `c`. */
bindingset[c, rk]
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) { any() }
@@ -128,10 +128,30 @@ SummaryComponent interpretComponentSpecific(AccessPathToken c) {
)
}
/** Gets the textual representation of a summary component in the format used for flow summaries. */
string getComponentSpecific(SummaryComponent sc) {
sc = TContentSummaryComponent(any(ListElementContent c)) and
result = "ListElement"
private string getContentSpecific(Content cs) {
cs = TListElementContent() and result = "ListElement"
or
cs = TSetElementContent() and result = "SetElement"
or
exists(int index |
cs = TTupleElementContent(index) and result = "TupleElement[" + index.toString() + "]"
)
or
exists(string key |
cs = TDictionaryElementContent(key) and result = "DictionaryElement[" + key + "]"
)
or
cs = TDictionaryElementAnyContent() and result = "DictionaryElementAny"
or
exists(string attr | cs = TAttributeContent(attr) and result = "Attribute[" + attr + "]")
}
/** Gets the textual representation of a summary component in the format used for MaD models. */
string getMadRepresentationSpecific(SummaryComponent sc) {
exists(Content c |
sc = TContentSummaryComponent(c) and
result = getContentSpecific(c)
)
}
/** Gets the textual representation of a parameter position in the format used for flow summaries. */

View File

@@ -0,0 +1,391 @@
/**
* Provides the implementation of type tracking steps through flow summaries.
* To use this, you must implement the `Input` signature. You can then use the predicates in the `Output`
* signature to implement the predicates of the same names inside `TypeTrackerSpecific.qll`.
*/
/** The classes and predicates needed to generate type-tracking steps from summaries. */
signature module Input {
// Dataflow nodes
class Node;
// Content
class TypeTrackerContent;
class TypeTrackerContentFilter;
// Relating content and filters
/**
* Gets a content filter to use for a `WithoutContent[content]` step, (data is not allowed to be stored in `content`)
* or has no result if
* the step should be treated as ordinary flow.
*
* `WithoutContent` is often used to perform strong updates on individual collection elements, but for
* type-tracking this is rarely beneficial and quite expensive. However, `WithoutContent` can be quite useful
* for restricting the type of an object, and in these cases we translate it to a filter.
*/
TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content);
/**
* Gets a content filter to use for a `WithContent[content]` step, (data must be stored in `content`)
* or has no result if
* the step cannot be handled by type-tracking.
*
* `WithContent` is often used to perform strong updates on individual collection elements (or rather
* to preserve those that didn't get updated). But for type-tracking this is rarely beneficial and quite expensive.
* However, `WithContent` can be quite useful for restricting the type of an object, and in these cases we translate it to a filter.
*/
TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content);
// Summaries and their stacks
class SummaryComponent;
class SummaryComponentStack {
SummaryComponent head();
}
/** Gets a singleton stack containing `component`. */
SummaryComponentStack singleton(SummaryComponent component);
/**
* Gets the stack obtained by pushing `head` onto `tail`.
*/
SummaryComponentStack push(SummaryComponent head, SummaryComponentStack tail);
/** Gets a singleton stack representing a return. */
SummaryComponent return();
// Relating content to summaries
/** Gets a summary component for content `c`. */
SummaryComponent content(TypeTrackerContent contents);
/** Gets a summary component where data is not allowed to be stored in `contents`. */
SummaryComponent withoutContent(TypeTrackerContent contents);
/** Gets a summary component where data must be stored in `contents`. */
SummaryComponent withContent(TypeTrackerContent contents);
// Callables
class SummarizedCallable {
predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
);
}
// Relating nodes to summaries
/** Gets a dataflow node respresenting the argument of `call` indicated by `arg`. */
Node argumentOf(Node call, SummaryComponent arg);
/** Gets a dataflow node respresenting the parameter of `callable` indicated by `param`. */
Node parameterOf(Node callable, SummaryComponent param);
/** Gets a dataflow node respresenting the return of `callable` indicated by `return`. */
Node returnOf(Node callable, SummaryComponent return);
// Relating callables to nodes
/** Gets a dataflow node respresenting a call to `callable`. */
Node callTo(SummarizedCallable callable);
}
/**
* The predicates provided by a summary type tracker.
* These are meant to be used in `TypeTrackerSpecific.qll`
* inside the predicates of the same names.
*/
signature module Output<Input I> {
/**
* Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph.
*/
predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo);
/**
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
*/
predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content);
/**
* Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
*/
predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content);
/**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/
predicate basicLoadStoreStep(
I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent,
I::TypeTrackerContent storeContent
);
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
*/
predicate basicWithoutContentStep(
I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
);
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
*/
predicate basicWithContentStep(
I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
);
}
/**
* Implementation of the summary type tracker, that is type tracking through flow summaries.
*/
module SummaryFlow<Input I> implements Output<I> {
pragma[nomagic]
private predicate isNonLocal(I::SummaryComponent component) {
component = I::content(_)
or
component = I::withContent(_)
}
pragma[nomagic]
private predicate hasLoadSummary(
I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input,
I::SummaryComponentStack output
) {
callable.propagatesFlow(I::push(I::content(contents), input), output, true) and
not isNonLocal(input.head()) and
not isNonLocal(output.head())
}
pragma[nomagic]
private predicate hasStoreSummary(
I::SummarizedCallable callable, I::TypeTrackerContent contents, I::SummaryComponentStack input,
I::SummaryComponentStack output
) {
not isNonLocal(input.head()) and
not isNonLocal(output.head()) and
(
callable.propagatesFlow(input, I::push(I::content(contents), output), true)
or
// Allow the input to start with an arbitrary WithoutContent[X].
// Since type-tracking only tracks one content deep, and we're about to store into another content,
// we're already preventing the input from being in a content.
callable
.propagatesFlow(I::push(I::withoutContent(_), input),
I::push(I::content(contents), output), true)
)
}
pragma[nomagic]
private predicate hasLoadStoreSummary(
I::SummarizedCallable callable, I::TypeTrackerContent loadContents,
I::TypeTrackerContent storeContents, I::SummaryComponentStack input,
I::SummaryComponentStack output
) {
callable
.propagatesFlow(I::push(I::content(loadContents), input),
I::push(I::content(storeContents), output), true) and
not isNonLocal(input.head()) and
not isNonLocal(output.head())
}
pragma[nomagic]
private predicate hasWithoutContentSummary(
I::SummarizedCallable callable, I::TypeTrackerContentFilter filter,
I::SummaryComponentStack input, I::SummaryComponentStack output
) {
exists(I::TypeTrackerContent content |
callable.propagatesFlow(I::push(I::withoutContent(content), input), output, true) and
filter = I::getFilterFromWithoutContentStep(content) and
not isNonLocal(input.head()) and
not isNonLocal(output.head()) and
input != output
)
}
pragma[nomagic]
private predicate hasWithContentSummary(
I::SummarizedCallable callable, I::TypeTrackerContentFilter filter,
I::SummaryComponentStack input, I::SummaryComponentStack output
) {
exists(I::TypeTrackerContent content |
callable.propagatesFlow(I::push(I::withContent(content), input), output, true) and
filter = I::getFilterFromWithContentStep(content) and
not isNonLocal(input.head()) and
not isNonLocal(output.head()) and
input != output
)
}
private predicate componentLevelStep(I::SummaryComponent component) {
exists(I::TypeTrackerContent content |
component = I::withoutContent(content) and
not exists(I::getFilterFromWithoutContentStep(content))
)
}
/**
* Gets a data flow `I::Node` corresponding an argument or return value of `call`,
* as specified by `component`.
*/
bindingset[call, component]
private I::Node evaluateSummaryComponentLocal(I::Node call, I::SummaryComponent component) {
result = I::argumentOf(call, component)
or
component = I::return() and
result = call
}
/**
* Holds if `callable` is relevant for type-tracking and we therefore want `stack` to
* be evaluated locally at its call sites.
*/
pragma[nomagic]
private predicate dependsOnSummaryComponentStack(
I::SummarizedCallable callable, I::SummaryComponentStack stack
) {
exists(I::callTo(callable)) and
(
callable.propagatesFlow(stack, _, true)
or
callable.propagatesFlow(_, stack, true)
or
// include store summaries as they may skip an initial step at the input
hasStoreSummary(callable, _, stack, _)
)
or
dependsOnSummaryComponentStackCons(callable, _, stack)
}
pragma[nomagic]
private predicate dependsOnSummaryComponentStackCons(
I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail
) {
dependsOnSummaryComponentStack(callable, I::push(head, tail))
}
pragma[nomagic]
private predicate dependsOnSummaryComponentStackConsLocal(
I::SummarizedCallable callable, I::SummaryComponent head, I::SummaryComponentStack tail
) {
dependsOnSummaryComponentStackCons(callable, head, tail) and
not isNonLocal(head)
}
pragma[nomagic]
private predicate dependsOnSummaryComponentStackLeaf(
I::SummarizedCallable callable, I::SummaryComponent leaf
) {
dependsOnSummaryComponentStack(callable, I::singleton(leaf))
}
/**
* Gets a data flow I::Node corresponding to the local input or output of `call`
* identified by `stack`, if possible.
*/
pragma[nomagic]
private I::Node evaluateSummaryComponentStackLocal(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack stack
) {
exists(I::SummaryComponent component |
dependsOnSummaryComponentStackLeaf(callable, component) and
stack = I::singleton(component) and
call = I::callTo(callable) and
result = evaluateSummaryComponentLocal(call, component)
)
or
exists(I::Node prev, I::SummaryComponent head, I::SummaryComponentStack tail |
prev = evaluateSummaryComponentStackLocal(callable, call, tail) and
dependsOnSummaryComponentStackConsLocal(callable, pragma[only_bind_into](head),
pragma[only_bind_out](tail)) and
stack = I::push(pragma[only_bind_out](head), pragma[only_bind_out](tail))
|
result = I::parameterOf(prev, head)
or
result = I::returnOf(prev, head)
or
componentLevelStep(head) and
result = prev
)
}
// Implement Output
predicate levelStepNoCall(I::Node nodeFrom, I::Node nodeTo) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
|
callable.propagatesFlow(input, output, true) and
call = I::callTo(callable) and
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
)
}
predicate basicLoadStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
|
hasLoadSummary(callable, content, pragma[only_bind_into](input),
pragma[only_bind_into](output)) and
call = I::callTo(callable) and
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
)
}
predicate basicStoreStep(I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent content) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
|
hasStoreSummary(callable, content, pragma[only_bind_into](input),
pragma[only_bind_into](output)) and
call = I::callTo(callable) and
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
)
}
predicate basicLoadStoreStep(
I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContent loadContent,
I::TypeTrackerContent storeContent
) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
|
hasLoadStoreSummary(callable, loadContent, storeContent, pragma[only_bind_into](input),
pragma[only_bind_into](output)) and
call = I::callTo(callable) and
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
)
}
predicate basicWithoutContentStep(
I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
|
hasWithoutContentSummary(callable, filter, pragma[only_bind_into](input),
pragma[only_bind_into](output)) and
call = I::callTo(callable) and
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
)
}
predicate basicWithContentStep(
I::Node nodeFrom, I::Node nodeTo, I::TypeTrackerContentFilter filter
) {
exists(
I::SummarizedCallable callable, I::Node call, I::SummaryComponentStack input,
I::SummaryComponentStack output
|
hasWithContentSummary(callable, filter, pragma[only_bind_into](input),
pragma[only_bind_into](output)) and
call = I::callTo(callable) and
nodeFrom = evaluateSummaryComponentStackLocal(callable, call, input) and
nodeTo = evaluateSummaryComponentStackLocal(callable, call, output)
)
}
}

View File

@@ -57,7 +57,9 @@ private module Cached {
or
asyncWithStep(nodeFrom, nodeTo)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom
.(DataFlowPrivate::FlowSummaryNode)
.getSummaryNode(), nodeTo.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false)
}
}
@@ -183,30 +185,6 @@ predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// 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)
or
// functions operating on collections
exists(DataFlow::CallCfgNode call | call = nodeTo |
call = API::builtin(["sorted", "reversed", "iter", "next"]).getACall() and
call.getArg(0) = nodeFrom
)
or
// methods
exists(DataFlow::MethodCallNode call, string methodName | call = nodeTo |
methodName in [
// general
"copy", "pop",
// dict
"values", "items", "get", "popitem"
] and
call.calls(nodeFrom, methodName)
)
or
// list.append, set.add
exists(DataFlow::MethodCallNode call, DataFlow::Node obj |
call.calls(obj, ["append", "add"]) and
obj = nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() and
call.getArg(0) = nodeFrom
)
}
/**

View File

@@ -235,17 +235,6 @@ private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) {
step(nodeFrom, _, summary)
}
bindingset[nodeFrom, t]
pragma[inline_late]
pragma[noopt]
private TypeTracker stepInlineLate(TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
exists(StepSummary summary |
stepProj(nodeFrom, summary) and
result = t.append(summary) and
step(nodeFrom, nodeTo, summary)
)
}
private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
smallstepNoCall(nodeFrom, nodeTo, summary)
or
@@ -257,17 +246,6 @@ private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
smallstep(nodeFrom, _, summary)
}
bindingset[nodeFrom, t]
pragma[inline_late]
pragma[noopt]
private TypeTracker smallstepInlineLate(TypeTracker t, Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
smallstepProj(nodeFrom, summary) and
result = t.append(summary) and
smallstep(nodeFrom, nodeTo, summary)
)
}
/**
* Holds if `nodeFrom` is being written to the `content` of the object in `nodeTo`.
*
@@ -501,9 +479,26 @@ class TypeTracker extends TTypeTracker {
* Gets the summary that corresponds to having taken a forwards
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*/
pragma[inline]
bindingset[nodeFrom, this]
pragma[inline_late]
pragma[noopt]
TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
result = stepInlineLate(this, nodeFrom, nodeTo)
exists(StepSummary summary |
stepProj(nodeFrom, summary) and
result = this.append(summary) and
step(nodeFrom, nodeTo, summary)
)
}
bindingset[nodeFrom, this]
pragma[inline_late]
pragma[noopt]
private TypeTracker smallstepNoSimpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
smallstepProj(nodeFrom, summary) and
result = this.append(summary) and
smallstep(nodeFrom, nodeTo, summary)
)
}
/**
@@ -532,7 +527,7 @@ class TypeTracker extends TTypeTracker {
*/
pragma[inline]
TypeTracker smallstep(Node nodeFrom, Node nodeTo) {
result = smallstepInlineLate(this, nodeFrom, nodeTo)
result = this.smallstepNoSimpleLocalFlowStep(nodeFrom, nodeTo)
or
simpleLocalFlowStep(nodeFrom, nodeTo) and
result = this
@@ -552,34 +547,10 @@ private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) {
step(_, nodeTo, summary)
}
bindingset[nodeTo, t]
pragma[inline_late]
pragma[noopt]
private TypeBackTracker backStepInlineLate(
TypeBackTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo
) {
exists(StepSummary summary |
backStepProj(nodeTo, summary) and
result = t.prepend(summary) and
step(nodeFrom, nodeTo, summary)
)
}
private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) {
smallstep(_, nodeTo, summary)
}
bindingset[nodeTo, t]
pragma[inline_late]
pragma[noopt]
private TypeBackTracker backSmallstepInlineLate(TypeBackTracker t, Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
backSmallstepProj(nodeTo, summary) and
result = t.prepend(summary) and
smallstep(nodeFrom, nodeTo, summary)
)
}
/**
* A summary of the steps needed to back-track a use of a value to a given dataflow node.
*
@@ -661,9 +632,26 @@ class TypeBackTracker extends TTypeBackTracker {
* Gets the summary that corresponds to having taken a backwards
* heap and/or inter-procedural step from `nodeTo` to `nodeFrom`.
*/
pragma[inline]
bindingset[nodeTo, result]
pragma[inline_late]
pragma[noopt]
TypeBackTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
this = backStepInlineLate(result, nodeFrom, nodeTo)
exists(StepSummary summary |
backStepProj(nodeTo, summary) and
this = result.prepend(summary) and
step(nodeFrom, nodeTo, summary)
)
}
bindingset[nodeTo, result]
pragma[inline_late]
pragma[noopt]
private TypeBackTracker smallstepNoSimpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
backSmallstepProj(nodeTo, summary) and
this = result.prepend(summary) and
smallstep(nodeFrom, nodeTo, summary)
)
}
/**
@@ -692,7 +680,7 @@ class TypeBackTracker extends TTypeBackTracker {
*/
pragma[inline]
TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) {
this = backSmallstepInlineLate(result, nodeFrom, nodeTo)
this = this.smallstepNoSimpleLocalFlowStep(nodeFrom, nodeTo)
or
simpleLocalFlowStep(nodeFrom, nodeTo) and
this = result

View File

@@ -61,7 +61,9 @@ predicate capturedJumpStep(Node nodeFrom, Node nodeTo) {
predicate levelStepCall(Node nodeFrom, Node nodeTo) { none() }
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */
predicate levelStepNoCall(Node nodeFrom, Node nodeTo) { none() }
predicate levelStepNoCall(Node nodeFrom, Node nodeTo) {
TypeTrackerSummaryFlow::levelStepNoCall(nodeFrom, nodeTo)
}
/**
* Gets the name of a possible piece of content. For Python, this is currently only attribute names,
@@ -108,6 +110,12 @@ predicate basicStoreStep(Node nodeFrom, Node nodeTo, string content) {
nodeFrom = a.getValue() and
nodeTo = a.getObject()
)
or
exists(DataFlowPublic::ContentSet contents |
contents.(DataFlowPublic::AttributeContent).getAttribute() = content
|
TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, contents)
)
}
/**
@@ -119,13 +127,24 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, string content) {
nodeFrom = a.getObject() and
nodeTo = a
)
or
exists(DataFlowPublic::ContentSet contents |
contents.(DataFlowPublic::AttributeContent).getAttribute() = content
|
TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, contents)
)
}
/**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/
predicate basicLoadStoreStep(Node nodeFrom, Node nodeTo, string loadContent, string storeContent) {
none()
exists(DataFlowPublic::ContentSet loadContents, DataFlowPublic::ContentSet storeContents |
loadContents.(DataFlowPublic::AttributeContent).getAttribute() = loadContent and
storeContents.(DataFlowPublic::AttributeContent).getAttribute() = storeContent
|
TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContents, storeContents)
)
}
/**
@@ -144,3 +163,93 @@ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter)
class Boolean extends boolean {
Boolean() { this = true or this = false }
}
private import SummaryTypeTracker as SummaryTypeTracker
private import semmle.python.dataflow.new.FlowSummary as FlowSummary
private import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch
pragma[noinline]
private predicate argumentPositionMatch(
DataFlowPublic::CallCfgNode call, DataFlowPublic::Node arg,
DataFlowDispatch::ParameterPosition ppos
) {
exists(DataFlowDispatch::ArgumentPosition apos |
DataFlowDispatch::parameterMatch(ppos, apos) and
DataFlowDispatch::normalCallArg(call.getNode(), arg, apos)
)
}
private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
// Dataflow nodes
class Node = DataFlowPublic::Node;
// Content
class TypeTrackerContent = DataFlowPublic::ContentSet;
class TypeTrackerContentFilter = ContentFilter;
TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content) { none() }
TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content) { none() }
// Callables
class SummarizedCallable = FlowSummary::SummarizedCallable;
// Summaries and their stacks
class SummaryComponent = FlowSummary::SummaryComponent;
class SummaryComponentStack = FlowSummary::SummaryComponentStack;
predicate singleton = FlowSummary::SummaryComponentStack::singleton/1;
predicate push = FlowSummary::SummaryComponentStack::push/2;
// Relating content to summaries
predicate content = FlowSummary::SummaryComponent::content/1;
SummaryComponent withoutContent(TypeTrackerContent contents) { none() }
SummaryComponent withContent(TypeTrackerContent contents) { none() }
predicate return = FlowSummary::SummaryComponent::return/0;
// Relating nodes to summaries
Node argumentOf(Node call, SummaryComponent arg) {
exists(DataFlowDispatch::ParameterPosition pos |
arg = FlowSummary::SummaryComponent::argument(pos) and
argumentPositionMatch(call, result, pos)
)
}
Node parameterOf(Node callable, SummaryComponent param) {
exists(
DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos, Parameter p
|
param = FlowSummary::SummaryComponent::parameter(apos) and
DataFlowDispatch::parameterMatch(ppos, apos) and
// pick the SsaNode rather than the CfgNode
result.asVar().getDefinition().(ParameterDefinition).getParameter() = p and
(
exists(int i | ppos.isPositional(i) |
p = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getArg(i)
)
or
exists(string name | ppos.isKeyword(name) |
p = callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getArgByName(name)
)
)
)
}
Node returnOf(Node callable, SummaryComponent return) {
return = FlowSummary::SummaryComponent::return() and
// `result` should be the return value of a callable expression (lambda or function) referenced by `callable`
result.asCfgNode() =
callable.getALocalSource().asExpr().(CallableExpr).getInnerScope().getAReturnValueFlowNode()
}
// Relating callables to nodes
Node callTo(SummarizedCallable callable) { result = callable.getACallSimple() }
}
private module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow<SummaryTypeTrackerInput>;

View File

@@ -534,9 +534,6 @@ module PrivateDjango {
/** Gets a reference to the `django` module. */
API::Node django() { result = API::moduleImport("django") }
/** DEPRECATED: Alias for `DjangoImpl` */
deprecated module django = DjangoImpl;
/** Provides models for the `django` module. */
module DjangoImpl {
// -------------------------------------------------------------------------
@@ -552,9 +549,6 @@ module PrivateDjango {
DjangoDb() { this = API::moduleImport("django").getMember("db") }
}
/** DEPRECATED: Alias for `DB` */
deprecated module db = DB;
/** Provides models for the `django.db` module. */
module DB {
/** Gets a reference to the `django.db.connection` object. */
@@ -571,9 +565,6 @@ module PrivateDjango {
/** Gets a reference to the `django.db.models` module. */
API::Node models() { result = db().getMember("models") }
/** DEPRECATED: Alias for `Models` */
deprecated module models = Models;
/** Provides models for the `django.db.models` module. */
module Models {
/**
@@ -819,9 +810,6 @@ module PrivateDjango {
/** Gets a reference to the `django.db.models.expressions` module. */
API::Node expressions() { result = models().getMember("expressions") }
/** DEPRECATED: Alias for `Expressions` */
deprecated module expressions = Expressions;
/** Provides models for the `django.db.models.expressions` module. */
module Expressions {
/** Provides models for the `django.db.models.expressions.RawSql` class. */
@@ -858,9 +846,6 @@ module PrivateDjango {
instance(DataFlow::TypeTracker::end(), sql).flowsTo(result)
}
}
/** DEPRECATED: Alias for RawSql */
deprecated module RawSQL = RawSql;
}
/** This internal module provides data-flow modeling of Django ORM. */
@@ -1099,9 +1084,6 @@ module PrivateDjango {
/** Gets a reference to the `django.urls` module. */
API::Node urls() { result = django().getMember("urls") }
/** DEPRECATED: Alias for `Urls` */
deprecated module urls = Urls;
/** Provides models for the `django.urls` module */
module Urls {
/**
@@ -1123,14 +1105,8 @@ module PrivateDjango {
/** Gets a reference to the `django.conf` module. */
API::Node conf() { result = django().getMember("conf") }
/** DEPRECATED: Alias for `Conf` */
deprecated module conf = Conf;
/** Provides models for the `django.conf` module */
module Conf {
/** DEPRECATED: Alias for `ConfUrls` */
deprecated module conf_urls = ConfUrls;
/** Provides models for the `django.conf.urls` module */
module ConfUrls {
// -------------------------------------------------------------------------
@@ -1166,9 +1142,6 @@ module PrivateDjango {
/** Gets a reference to the `django.http.request` module. */
API::Node request() { result = http().getMember("request") }
/** DEPRECATED: Alias for `Request` */
deprecated module request = Request;
/** Provides models for the `django.http.request` module. */
module Request {
/**
@@ -1331,9 +1304,6 @@ module PrivateDjango {
/** Gets a reference to the `django.http.response` module. */
API::Node response() { result = http().getMember("response") }
/** DEPRECATED: Alias for `Response` */
deprecated module response = Response;
/** Provides models for the `django.http.response` module */
module Response {
/**
@@ -2189,9 +2159,6 @@ module PrivateDjango {
/** Gets a reference to the `django.shortcuts` module. */
API::Node shortcuts() { result = django().getMember("shortcuts") }
/** DEPRECATED: Alias for `Shortcuts` */
deprecated module shortcuts = Shortcuts;
/** Provides models for the `django.shortcuts` module */
module Shortcuts {
/**

View File

@@ -37,9 +37,6 @@ private module FastApi {
}
}
/** DEPRECATED: Alias for ApiRouter */
deprecated module APIRouter = ApiRouter;
// ---------------------------------------------------------------------------
// routing modeling
// ---------------------------------------------------------------------------

View File

@@ -13,6 +13,7 @@ private import semmle.python.frameworks.Stdlib
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
private import semmle.python.security.dataflow.PathInjectionCustomizations
private import semmle.python.dataflow.new.FlowSummary
/**
* Provides models for the `flask` PyPI package.
@@ -587,4 +588,57 @@ module Flask {
private class FlaskLogger extends Stdlib::Logger::InstanceSource {
FlaskLogger() { this = FlaskApp::instance().getMember("logger").asSource() }
}
/**
* A flow summary for `flask.render_template_string`.
*
* see https://flask.palletsprojects.com/en/2.3.x/api/#flask.render_template_string
*/
private class RenderTemplateStringSummary extends SummarizedCallable {
RenderTemplateStringSummary() { this = "flask.render_template_string" }
override DataFlow::CallCfgNode getACall() {
result = API::moduleImport("flask").getMember("render_template_string").getACall()
}
override DataFlow::ArgumentNode getACallback() {
result =
API::moduleImport("flask")
.getMember("render_template_string")
.getAValueReachableFromSource()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false
}
}
/**
* A flow summary for `flask.stream_template_string`.
*
* see https://flask.palletsprojects.com/en/2.3.x/api/#flask.stream_template_string
*/
private class StreamTemplateStringSummary extends SummarizedCallable {
StreamTemplateStringSummary() { this = "flask.stream_template_string" }
override DataFlow::CallCfgNode getACall() {
result = API::moduleImport("flask").getMember("stream_template_string").getACall()
}
override DataFlow::ArgumentNode getACallback() {
result =
API::moduleImport("flask")
.getMember("stream_template_string")
.getAValueReachableFromSource()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0]" and
// Technically it's `Iterator[str]`, but list will do :)
output = "ReturnValue.ListElement" and
preservesValue = false
}
}
}

View File

@@ -359,7 +359,4 @@ private module RestFramework {
override string getMimetypeDefault() { none() }
}
}
/** DEPRECATED: Alias for ApiException */
deprecated module APIException = ApiException;
}

View File

@@ -169,9 +169,6 @@ module SqlAlchemy {
DataFlow::Node instance() { instance(DataFlow::TypeTracker::end()).flowsTo(result) }
}
/** DEPRECATED: Alias for DBApiConnection */
deprecated module DBAPIConnection = DBApiConnection;
/**
* Provides models for the `sqlalchemy.orm.Session` class
*

View File

@@ -130,9 +130,6 @@ module Stdlib {
}
}
/** DEPRECATED: Alias for HttpMessage */
deprecated module HTTPMessage = HttpMessage;
/**
* Provides models for the `http.cookies.Morsel` class
*
@@ -1821,9 +1818,6 @@ private module StdlibPrivate {
/** Gets a reference to the `BaseHttpServer` module. */
API::Node baseHttpServer() { result = API::moduleImport("BaseHTTPServer") }
/** DEPRECATED: Alias for baseHttpServer */
deprecated API::Node baseHTTPServer() { result = baseHttpServer() }
/** Provides models for the `BaseHttpServer` module. */
module BaseHttpServer {
/**
@@ -1833,23 +1827,14 @@ private module StdlibPrivate {
/** Gets a reference to the `BaseHttpServer.BaseHttpRequestHandler` class. */
API::Node classRef() { result = baseHttpServer().getMember("BaseHTTPRequestHandler") }
}
/** DEPRECATED: Alias for BaseHttpRequestHandler */
deprecated module BaseHTTPRequestHandler = BaseHttpRequestHandler;
}
/** DEPRECATED: Alias for BaseHttpServer */
deprecated module BaseHTTPServer = BaseHttpServer;
// ---------------------------------------------------------------------------
// SimpleHTTPServer (Python 2 only)
// ---------------------------------------------------------------------------
/** Gets a reference to the `SimpleHttpServer` module. */
API::Node simpleHttpServer() { result = API::moduleImport("SimpleHTTPServer") }
/** DEPRECATED: Alias for simpleHttpServer */
deprecated API::Node simpleHTTPServer() { result = simpleHttpServer() }
/** Provides models for the `SimpleHttpServer` module. */
module SimpleHttpServer {
/**
@@ -1859,23 +1844,14 @@ private module StdlibPrivate {
/** Gets a reference to the `SimpleHttpServer.SimpleHttpRequestHandler` class. */
API::Node classRef() { result = simpleHttpServer().getMember("SimpleHTTPRequestHandler") }
}
/** DEPRECATED: Alias for SimpleHttpRequestHandler */
deprecated module SimpleHTTPRequestHandler = SimpleHttpRequestHandler;
}
/** DEPRECATED: Alias for SimpleHttpServer */
deprecated module SimpleHTTPServer = SimpleHttpServer;
// ---------------------------------------------------------------------------
// CGIHTTPServer (Python 2 only)
// ---------------------------------------------------------------------------
/** Gets a reference to the `CGIHTTPServer` module. */
API::Node cgiHttpServer() { result = API::moduleImport("CGIHTTPServer") }
/** DEPRECATED: Alias for cgiHttpServer */
deprecated API::Node cgiHTTPServer() { result = cgiHttpServer() }
/** Provides models for the `CGIHTTPServer` module. */
module CgiHttpServer {
/**
@@ -1919,9 +1895,6 @@ private module StdlibPrivate {
API::Node classRef() { result = server().getMember("BaseHTTPRequestHandler") }
}
/** DEPRECATED: Alias for BaseHttpRequestHandler */
deprecated module BaseHTTPRequestHandler = BaseHttpRequestHandler;
/**
* Provides models for the `http.server.SimpleHTTPRequestHandler` class (Python 3 only).
*
@@ -1932,9 +1905,6 @@ private module StdlibPrivate {
API::Node classRef() { result = server().getMember("SimpleHTTPRequestHandler") }
}
/** DEPRECATED: Alias for SimpleHttpRequestHandler */
deprecated module SimpleHTTPRequestHandler = SimpleHttpRequestHandler;
/**
* Provides models for the `http.server.CGIHTTPRequestHandler` class (Python 3 only).
*
@@ -1978,9 +1948,6 @@ private module StdlibPrivate {
HttpRequestHandlerClassDef() { this.getParent() = subclassRef().asSource().asExpr() }
}
/** DEPRECATED: Alias for HttpRequestHandlerClassDef */
deprecated class HTTPRequestHandlerClassDef = HttpRequestHandlerClassDef;
/**
* A source of instances of the `BaseHTTPRequestHandler` class or any subclass, extend this class to model new instances.
*
@@ -2352,9 +2319,6 @@ private module StdlibPrivate {
}
}
/** DEPRECATED: Alias for HttpConnection */
deprecated module HTTPConnection = HttpConnection;
/**
* Provides models for the `http.client.HTTPResponse` class
*
@@ -2424,9 +2388,6 @@ private module StdlibPrivate {
}
}
/** DEPRECATED: Alias for HttpResponse */
deprecated module HTTPResponse = HttpResponse;
// ---------------------------------------------------------------------------
// sqlite3
// ---------------------------------------------------------------------------
@@ -3922,6 +3883,9 @@ private module StdlibPrivate {
}
}
// ---------------------------------------------------------------------------
// Flow summaries for functions operating on containers
// ---------------------------------------------------------------------------
/** A flow summary for `reversed`. */
class ReversedSummary extends SummarizedCallable {
ReversedSummary() { this = "builtins.reversed" }
@@ -3933,9 +3897,284 @@ private module StdlibPrivate {
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[0].ListElement" and
(
input = "Argument[0].ListElement"
or
input = "Argument[0].SetElement"
or
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue.ListElement" and
preservesValue = true
or
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false
}
}
/** A flow summary for `sorted`. */
class SortedSummary extends SummarizedCallable {
SortedSummary() { this = "builtins.sorted" }
override DataFlow::CallCfgNode getACall() { result = API::builtin("sorted").getACall() }
override DataFlow::ArgumentNode getACallback() {
result = API::builtin("sorted").getAValueReachableFromSource()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
exists(string content |
content = "ListElement"
or
content = "SetElement"
or
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
content = "TupleElement[" + i.toString() + "]"
)
|
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
input = "Argument[0]." + content and
output = "ReturnValue.ListElement" and
preservesValue = true
)
or
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false
}
}
/** A flow summary for `iter`. */
class IterSummary extends SummarizedCallable {
IterSummary() { this = "builtins.iter" }
override DataFlow::CallCfgNode getACall() { result = API::builtin("iter").getACall() }
override DataFlow::ArgumentNode getACallback() {
result = API::builtin("iter").getAValueReachableFromSource()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
(
input = "Argument[0].ListElement"
or
input = "Argument[0].SetElement"
or
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue.ListElement" and
preservesValue = true
or
input = "Argument[0]" and
output = "ReturnValue" and
preservesValue = false
}
}
/** A flow summary for `next`. */
class NextSummary extends SummarizedCallable {
NextSummary() { this = "builtins.next" }
override DataFlow::CallCfgNode getACall() { result = API::builtin("next").getACall() }
override DataFlow::ArgumentNode getACallback() {
result = API::builtin("next").getAValueReachableFromSource()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
(
input = "Argument[0].ListElement"
or
input = "Argument[0].SetElement"
or
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
input = "Argument[0].TupleElement[" + i.toString() + "]"
)
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
) and
output = "ReturnValue" and
preservesValue = true
or
input = "Argument[1]" and
output = "ReturnValue" and
preservesValue = true
}
}
// ---------------------------------------------------------------------------
// Flow summaries for container methods
// ---------------------------------------------------------------------------
/** A flow summary for `copy`. */
class CopySummary extends SummarizedCallable {
CopySummary() { this = "collection.copy" }
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).getMethodName() = "copy"
}
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
exists(string content |
content = "ListElement"
or
content = "SetElement"
or
exists(DataFlow::TupleElementContent tc, int i | i = tc.getIndex() |
content = "TupleElement[" + i.toString() + "]"
)
or
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
content = "DictionaryElement[" + key + "]"
)
|
input = "Argument[self]." + content and
output = "ReturnValue." + content and
preservesValue = true
)
or
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = true
}
}
/**
* A flow summary for `pop` either for list or set.
* This ignores the index if given, since content is
* imprecise anyway.
*
* I also handles the default value when `pop` is called
* on a dictionary, since that also does not depend on the key.
*/
class PopSummary extends SummarizedCallable {
PopSummary() { this = "collection.pop" }
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).getMethodName() = "pop"
}
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[self].ListElement" and
output = "ReturnValue" and
preservesValue = true
or
input = "Argument[self].SetElement" and
output = "ReturnValue" and
preservesValue = true
or
// default value for dictionary
input = "Argument[1]" and
output = "ReturnValue" and
preservesValue = true
or
// transfer taint on self to return value
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = false
}
}
/** A flow summary for `dict.pop` */
class DictPopSummary extends SummarizedCallable {
string key;
DictPopSummary() {
this = "dict.pop(" + key + ")" and
exists(DataFlow::DictionaryElementContent dc | key = dc.getKey())
}
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).getMethodName() = "pop" and
result.getArg(0).getALocalSource().asExpr().(StrConst).getText() = key
}
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue" and
preservesValue = true
}
}
/** A flow summary for `dict.get` at specific content. */
class DictGetSummary extends SummarizedCallable {
string key;
DictGetSummary() {
this = "dict.get(" + key + ")" and
exists(DataFlow::DictionaryElementContent dc | key = dc.getKey())
}
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).getMethodName() = "get" and
result.getArg(0).getALocalSource().asExpr().(StrConst).getText() = key
}
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue" and
preservesValue = true
or
// optional default value
input = "Argument[1]" and
output = "ReturnValue" and
preservesValue = true
}
}
/** A flow summary for `dict.get` disregarding content. */
class DictGetAnySummary extends SummarizedCallable {
DictGetAnySummary() { this = "dict.get" }
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).getMethodName() = "get"
}
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
// default value
input = "Argument[1]" and
output = "ReturnValue" and
preservesValue = true
or
// transfer taint from self to return value
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = false
}
}
/** A flow summary for `dict.popitem` */
class DictPopitemSummary extends SummarizedCallable {
DictPopitemSummary() { this = "dict.popitem" }
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).getMethodName() = "popitem"
}
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue.TupleElement[1]" and
preservesValue = true
// TODO: put `key` into "ReturnValue.TupleElement[0]"
)
}
}
@@ -3962,6 +4201,177 @@ private module StdlibPrivate {
preservesValue = true
}
}
/**
* A flow summary for `dict.setdefault` at specific content.
* See https://docs.python.org/3.10/library/stdtypes.html#dict.setdefault
* This summary handles read and store steps. See `DictSetdefaultSummary`
* for the dataflow steps.
*/
class DictSetdefaultKeySummary extends SummarizedCallable {
string key;
DictSetdefaultKeySummary() {
this = "dict.setdefault(" + key + ")" and
exists(DataFlow::DictionaryElementContent dc | key = dc.getKey())
}
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).getMethodName() = "setdefault" and
result.getArg(0).getALocalSource().asExpr().(StrConst).getText() = key
}
override DataFlow::ArgumentNode getACallback() { none() }
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
// If key is in the dictionary, return its value.
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue" and
preservesValue = true
or
// If not, insert key with a value of default.
input = "Argument[1]" and
output = "ReturnValue.DictionaryElement[" + key + "]" and
preservesValue = true
}
}
/**
* A flow summary for `dict.values`.
*
* See https://docs.python.org/3.10/library/stdtypes.html#dict.values
*/
class DictValues extends SummarizedCallable {
DictValues() { this = "dict.values" }
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).calls(_, "values")
}
override DataFlow::ArgumentNode getACallback() {
result.(DataFlow::AttrRead).getAttributeName() = "values"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue.ListElement" and
preservesValue = true
)
or
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = false
}
}
/**
* A flow summary for `dict.keys`.
*
* See https://docs.python.org/3.10/library/stdtypes.html#dict.keys
*/
class DictKeys extends SummarizedCallable {
DictKeys() { this = "dict.keys" }
override DataFlow::CallCfgNode getACall() { result.(DataFlow::MethodCallNode).calls(_, "keys") }
override DataFlow::ArgumentNode getACallback() {
result.(DataFlow::AttrRead).getAttributeName() = "keys"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
// TODO: Once we have DictKeyContent, we need to transform that into ListElementContent
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = false
}
}
/**
* A flow summary for `dict.items`.
*
* See https://docs.python.org/3.10/library/stdtypes.html#dict.items
*/
class DictItems extends SummarizedCallable {
DictItems() { this = "dict.items" }
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).calls(_, "items")
}
override DataFlow::ArgumentNode getACallback() {
result.(DataFlow::AttrRead).getAttributeName() = "items"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
exists(DataFlow::DictionaryElementContent dc, string key | key = dc.getKey() |
input = "Argument[self].DictionaryElement[" + key + "]" and
output = "ReturnValue.ListElement.TupleElement[1]" and
preservesValue = true
)
or
// TODO: Add the keys to output list
input = "Argument[self]" and
output = "ReturnValue" and
preservesValue = false
}
}
/**
* A flow summary for `list.append`.
*
* See https://docs.python.org/3.10/library/stdtypes.html#typesseq-mutable
*/
class ListAppend extends SummarizedCallable {
ListAppend() { this = "list.append" }
override DataFlow::CallCfgNode getACall() {
result.(DataFlow::MethodCallNode).calls(_, "append")
}
override DataFlow::ArgumentNode getACallback() {
result.(DataFlow::AttrRead).getAttributeName() = "append"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
// newly added element added to this
input = "Argument[0]" and
output = "Argument[self].ListElement" and
preservesValue = true
or
// transfer taint from new element to this (TODO: remove in future when taint-handling is more in line with other languages)
input = "Argument[0]" and
output = "Argument[self]" and
preservesValue = false
}
}
/**
* A flow summary for `set.add`.
*
* See https://docs.python.org/3.10/library/stdtypes.html#frozenset.add
*/
class SetAdd extends SummarizedCallable {
SetAdd() { this = "set.add" }
override DataFlow::CallCfgNode getACall() { result.(DataFlow::MethodCallNode).calls(_, "add") }
override DataFlow::ArgumentNode getACallback() {
result.(DataFlow::AttrRead).getAttributeName() = "add"
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
// newly added element added to this
input = "Argument[0]" and
output = "Argument[self].SetElement" and
preservesValue = true
or
// transfer taint from new element to this (TODO: remove in future when taint-handling is more in line with other languages)
input = "Argument[0]" and
output = "Argument[self]" and
preservesValue = false
}
}
}
// ---------------------------------------------------------------------------

View File

@@ -64,9 +64,6 @@ module Tornado {
}
}
/** DEPRECATED: Alias for HttpHeaders */
deprecated module HTTPHeaders = HttpHeaders;
// ---------------------------------------------------------------------------
// tornado
// ---------------------------------------------------------------------------

View File

@@ -643,6 +643,15 @@ module ModelOutput {
baseNode = getInvocationFromPath(type, path)
}
/**
* Holds if a `baseNode` is a callable identified by the `type,path` part of a summary row.
*/
cached
predicate resolvedSummaryRefBase(string type, string path, API::Node baseNode) {
summaryModel(type, path, _, _, _) and
baseNode = getNodeFromPath(type, path)
}
/**
* Holds if `node` is seen as an instance of `type` due to a type definition
* contributed by a CSV model.
@@ -653,6 +662,17 @@ module ModelOutput {
import Cached
import Specific::ModelOutputSpecific
private import codeql.mad.ModelValidation as SharedModelVal
private module KindValConfig implements SharedModelVal::KindValidationConfigSig {
predicate summaryKind(string kind) { summaryModel(_, _, _, _, kind) }
predicate sinkKind(string kind) { sinkModel(_, _, kind) }
predicate sourceKind(string kind) { sourceModel(_, _, kind) }
}
private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
/**
* Gets an error message relating to an invalid CSV row in a model.
@@ -698,5 +718,8 @@ module ModelOutput {
not isValidNoArgumentTokenInIdentifyingAccessPath(token.getName()) and
result = "Invalid token '" + token + "' is missing its arguments, in access path: " + path
)
or
// Check for invalid model kinds
result = KindVal::getInvalidModelKind()
}
}

View File

@@ -1445,14 +1445,6 @@ module Expressions {
)
}
deprecated predicate subscriptPointsTo(
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode obj, ObjectInternal objvalue
) {
subscriptPointsTo(subscr, context, value, obj, objvalue) and
origin = subscr
}
pragma[noinline]
private predicate subscriptPointsTo(
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode obj,
@@ -1489,14 +1481,6 @@ module Expressions {
index = subscr.getIndex()
}
deprecated predicate binaryPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
binaryPointsTo(b, context, value, operand, opvalue) and
origin = b
}
/**
* Tracking too many binary expressions is likely to kill performance, so just say anything other than addition or bitwise or is 'unknown'.
*/
@@ -1521,14 +1505,6 @@ module Expressions {
)
}
deprecated predicate addPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
addPointsTo(b, context, value, operand, opvalue) and
origin = b
}
pragma[noinline]
private predicate addPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
@@ -1545,14 +1521,6 @@ module Expressions {
)
}
deprecated predicate bitOrPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
bitOrPointsTo(b, context, value, operand, opvalue) and
origin = b
}
pragma[noinline]
private predicate bitOrPointsTo(
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
@@ -1577,14 +1545,6 @@ module Expressions {
value = obj.intValue()
}
deprecated predicate unaryPointsTo(
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode operand, ObjectInternal opvalue
) {
unaryPointsTo(u, context, value, operand, opvalue) and
origin = u
}
pragma[noinline]
private predicate unaryPointsTo(
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
@@ -1603,14 +1563,6 @@ module Expressions {
)
}
deprecated predicate builtinCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
ControlFlowNode arg, ObjectInternal argvalue
) {
builtinCallPointsTo(call, context, value, arg, argvalue) and
origin = call
}
pragma[noinline]
private predicate builtinCallPointsTo(
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,

View File

@@ -1,54 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.SensitiveData
import semmle.python.dataflow.Files
import semmle.python.web.Http
deprecated module ClearTextStorage {
abstract class Sink extends TaintSink {
override predicate sinks(TaintKind kind) { kind instanceof SensitiveData }
}
class CookieStorageSink extends Sink {
CookieStorageSink() { any(CookieSet cookie).getValue() = this }
}
class FileStorageSink extends Sink {
FileStorageSink() {
exists(CallNode call, AttrNode meth, string name |
any(OpenFile fd).taints(meth.getObject(name)) and
call.getFunction() = meth and
call.getAnArg() = this
|
name = "write"
)
}
}
}
deprecated module ClearTextLogging {
abstract class Sink extends TaintSink {
override predicate sinks(TaintKind kind) { kind instanceof SensitiveData }
}
class PrintSink extends Sink {
PrintSink() {
exists(CallNode call |
call.getAnArg() = this and
call = Value::named("print").getACall()
)
}
}
class LoggingSink extends Sink {
LoggingSink() {
exists(CallNode call, AttrNode meth, string name |
call.getFunction() = meth and
meth.getObject(name).(NameNode).getId().matches("logg%") and
call.getAnArg() = this
|
name = ["error", "warn", "warning", "debug", "info"]
)
}
}
}

View File

@@ -1,139 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
private import semmle.python.security.SensitiveData
private import semmle.crypto.Crypto as CryptoLib
abstract deprecated class WeakCryptoSink extends TaintSink {
override predicate sinks(TaintKind taint) { taint instanceof SensitiveData }
}
/** Modeling the 'pycrypto' package https://github.com/dlitz/pycrypto (latest release 2013) */
deprecated module Pycrypto {
ModuleValue cipher(string name) { result = Module::named("Crypto.Cipher").attr(name) }
class CipherInstance extends TaintKind {
string name;
CipherInstance() {
this = "Crypto.Cipher." + name and
exists(cipher(name))
}
string getName() { result = name }
CryptoLib::CryptographicAlgorithm getAlgorithm() { result.getName() = name }
predicate isWeak() { this.getAlgorithm().isWeak() }
}
class CipherInstanceSource extends TaintSource {
CipherInstance instance;
CipherInstanceSource() {
exists(AttrNode attr |
this.(CallNode).getFunction() = attr and
attr.getObject("new").pointsTo(cipher(instance.getName()))
)
}
override string toString() { result = "Source of " + instance }
override predicate isSourceOf(TaintKind kind) { kind = instance }
}
class PycryptoWeakCryptoSink extends WeakCryptoSink {
string name;
PycryptoWeakCryptoSink() {
exists(CallNode call, AttrNode method, CipherInstance cipher |
call.getAnArg() = this and
call.getFunction() = method and
cipher.taints(method.getObject("encrypt")) and
cipher.isWeak() and
cipher.getName() = name
)
}
override string toString() { result = "Use of weak crypto algorithm " + name }
}
}
deprecated module Cryptography {
ModuleValue ciphers() {
result = Module::named("cryptography.hazmat.primitives.ciphers") and
result.isPackage()
}
class CipherClass extends ClassValue {
CipherClass() { ciphers().attr("Cipher") = this }
}
class AlgorithmClass extends ClassValue {
AlgorithmClass() { ciphers().attr("algorithms").attr(_) = this }
string getAlgorithmName() { result = this.declaredAttribute("name").(StringValue).getText() }
predicate isWeak() {
exists(CryptoLib::CryptographicAlgorithm algo |
algo.getName() = this.getAlgorithmName() and
algo.isWeak()
)
}
}
class CipherInstance extends TaintKind {
AlgorithmClass cls;
CipherInstance() { this = "cryptography.Cipher." + cls.getAlgorithmName() }
AlgorithmClass getAlgorithm() { result = cls }
predicate isWeak() { cls.isWeak() }
override TaintKind getTaintOfMethodResult(string name) {
name = "encryptor" and
result.(Encryptor).getAlgorithm() = this.getAlgorithm()
}
}
class CipherSource extends TaintSource {
CipherSource() { this.(CallNode).getFunction().pointsTo(any(CipherClass cls)) }
override predicate isSourceOf(TaintKind kind) {
this.(CallNode).getArg(0).pointsTo().getClass() = kind.(CipherInstance).getAlgorithm()
}
override string toString() { result = "cryptography.Cipher.source" }
}
class Encryptor extends TaintKind {
AlgorithmClass cls;
Encryptor() { this = "cryptography.encryptor." + cls.getAlgorithmName() }
AlgorithmClass getAlgorithm() { result = cls }
}
class CryptographyWeakCryptoSink extends WeakCryptoSink {
CryptographyWeakCryptoSink() {
exists(CallNode call, AttrNode method, Encryptor encryptor |
call.getAnArg() = this and
call.getFunction() = method and
encryptor.taints(method.getObject("update")) and
encryptor.getAlgorithm().isWeak()
)
}
override string toString() { result = "Use of weak crypto algorithm" }
}
}
deprecated private class CipherConfig extends TaintTracking::Configuration {
CipherConfig() { this = "Crypto cipher config" }
override predicate isSource(TaintTracking::Source source) {
source instanceof Pycrypto::CipherInstanceSource
or
source instanceof Cryptography::CipherSource
}
}

View File

@@ -1,103 +0,0 @@
/**
* Provides classes and predicates for tracking exceptions and information
* associated with exceptions.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
deprecated private Value traceback_function(string name) {
result = Module::named("traceback").attr(name)
}
/**
* This represents information relating to an exception, for instance the
* message, arguments or parts of the exception traceback.
*/
deprecated class ExceptionInfo extends StringKind {
ExceptionInfo() { this = "exception.info" }
override string repr() { result = "exception info" }
}
/**
* A class representing sources of information about
* execution state exposed in tracebacks and the like.
*/
abstract deprecated class ErrorInfoSource extends TaintSource { }
/**
* This kind represents exceptions themselves.
*/
deprecated class ExceptionKind extends TaintKind {
ExceptionKind() { this = "exception.kind" }
override string repr() { result = "exception" }
override TaintKind getTaintOfAttribute(string name) {
name = "args" and result instanceof ExceptionInfoSequence
or
name = "message" and result instanceof ExceptionInfo
}
}
/**
* A source of exception objects, either explicitly created, or captured by an
* `except` statement.
*/
deprecated class ExceptionSource extends ErrorInfoSource {
ExceptionSource() {
exists(ClassValue cls |
cls.getASuperType() = ClassValue::baseException() and
this.(ControlFlowNode).pointsTo().getClass() = cls
)
or
this = any(ExceptStmt s).getName().getAFlowNode()
}
override string toString() { result = "exception.source" }
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionKind }
}
/**
* Represents a sequence of pieces of information relating to an exception,
* for instance the contents of the `args` attribute, or the stack trace.
*/
deprecated class ExceptionInfoSequence extends SequenceKind {
ExceptionInfoSequence() { this.getItem() instanceof ExceptionInfo }
}
/**
* Represents calls to functions in the `traceback` module that return
* sequences of exception information.
*/
deprecated class CallToTracebackFunction extends ErrorInfoSource {
CallToTracebackFunction() {
exists(string name |
name in [
"extract_tb", "extract_stack", "format_list", "format_exception_only", "format_exception",
"format_tb", "format_stack"
]
|
this = traceback_function(name).getACall()
)
}
override string toString() { result = "exception.info.sequence.source" }
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfoSequence }
}
/**
* Represents calls to functions in the `traceback` module that return a single
* string of information about an exception.
*/
deprecated class FormattedTracebackSource extends ErrorInfoSource {
FormattedTracebackSource() { this = traceback_function("format_exc").getACall() }
override string toString() { result = "exception.info.source" }
override predicate isSourceOf(TaintKind kind) { kind instanceof ExceptionInfo }
}

View File

@@ -1,4 +1,4 @@
import python
import semmle.python.dataflow.TaintTracking
abstract class SqlInjectionSink extends TaintSink { }
abstract deprecated class SqlInjectionSink extends TaintSink { }

View File

@@ -1,118 +0,0 @@
/**
* Provides classes and predicates for identifying sensitive data and methods for security.
*
* 'Sensitive' data in general is anything that should not be sent around in unencrypted form. This
* library tries to guess where sensitive data may either be stored in a variable or produced by a
* method.
*
* In addition, there are methods that ought not to be executed or not in a fashion that the user
* can control. This includes authorization methods such as logins, and sending of data, etc.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.web.HttpRequest
import semmle.python.security.internal.SensitiveDataHeuristics
private import HeuristicNames
abstract deprecated class SensitiveData extends TaintKind {
bindingset[this]
SensitiveData() { this = this }
/** Gets the classification of this sensitive data taint kind. */
abstract SensitiveDataClassification getClassification();
}
deprecated module SensitiveData {
class Secret extends SensitiveData {
Secret() { this = "sensitive.data.secret" }
override string repr() { result = "a secret" }
override SensitiveDataClassification getClassification() {
result = SensitiveDataClassification::secret()
}
}
class Id extends SensitiveData {
Id() { this = "sensitive.data.id" }
override string repr() { result = "an ID" }
override SensitiveDataClassification getClassification() {
result = SensitiveDataClassification::id()
}
}
class Password extends SensitiveData {
Password() { this = "sensitive.data.password" }
override string repr() { result = "a password" }
override SensitiveDataClassification getClassification() {
result = SensitiveDataClassification::password()
}
}
class Certificate extends SensitiveData {
Certificate() { this = "sensitive.data.certificate" }
override string repr() { result = "a certificate or key" }
override SensitiveDataClassification getClassification() {
result = SensitiveDataClassification::certificate()
}
}
private SensitiveData fromFunction(Value func) {
nameIndicatesSensitiveData(func.getName(), result.getClassification())
}
abstract class Source extends TaintSource {
abstract string repr();
}
private class SensitiveCallSource extends Source {
SensitiveData data;
SensitiveCallSource() {
exists(Value callee | callee.getACall() = this | data = fromFunction(callee))
}
override predicate isSourceOf(TaintKind kind) { kind = data }
override string repr() { result = "a call returning " + data.repr() }
}
/** An access to a variable or property that might contain sensitive data. */
private class SensitiveVariableAccess extends SensitiveData::Source {
SensitiveData data;
SensitiveVariableAccess() {
nameIndicatesSensitiveData(this.(AttrNode).getName(), data.getClassification())
}
override predicate isSourceOf(TaintKind kind) { kind = data }
override string repr() { result = "an attribute or property containing " + data.repr() }
}
private class SensitiveRequestParameter extends SensitiveData::Source {
SensitiveData data;
SensitiveRequestParameter() {
this.(CallNode).getFunction().(AttrNode).getName() = "get" and
exists(StringValue sensitive |
this.(CallNode).getAnArg().pointsTo(sensitive) and
nameIndicatesSensitiveData(sensitive.getText(), data.getClassification())
)
}
override predicate isSourceOf(TaintKind kind) { kind = data }
override string repr() { result = "a request parameter containing " + data.repr() }
}
}
//Backwards compatibility
deprecated class SensitiveDataSource = SensitiveData::Source;

View File

@@ -1,95 +0,0 @@
/**
* DEPRECATED -- use flow state instead
*
* This defines a `PathGraph` where sinks from `TaintTracking::Configuration`s are identified with
* sources from `TaintTracking2::Configuration`s if they represent the same `ControlFlowNode`.
*
* Paths are then connected appropriately.
*/
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.DataFlow2
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.TaintTracking2
/**
* A `DataFlow::Node` that appears as a sink in Config1 and a source in Config2.
*/
private predicate crossoverNode(DataFlow::Node n) {
any(TaintTracking::Configuration t1).isSink(n) and
any(TaintTracking2::Configuration t2).isSource(n)
}
/**
* A new type which represents the union of the two sets of nodes.
*/
private newtype TCustomPathNode =
Config1Node(DataFlow::PathNode node1) { not crossoverNode(node1.getNode()) } or
Config2Node(DataFlow2::PathNode node2) { not crossoverNode(node2.getNode()) } or
CrossoverNode(DataFlow::Node node) { crossoverNode(node) }
/**
* DEPRECATED: Use flow state instead
*
* A class representing the set of all the path nodes in either config.
*/
deprecated class CustomPathNode extends TCustomPathNode {
/** Gets the PathNode if it is in Config1. */
DataFlow::PathNode asNode1() {
this = Config1Node(result) or this = CrossoverNode(result.getNode())
}
/** Gets the PathNode if it is in Config2. */
DataFlow2::PathNode asNode2() {
this = Config2Node(result) or this = CrossoverNode(result.getNode())
}
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
or
this.asNode2().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a textual representation of this element. */
string toString() {
result = this.asNode1().toString()
or
result = this.asNode2().toString()
}
}
/**
* DEPRECATED: Use flow state instead
*
* Holds if `(a,b)` is an edge in the graph of data flow path explanations.
*/
deprecated query predicate edges(CustomPathNode a, CustomPathNode b) {
// Edge is in Config1 graph
DataFlow::PathGraph::edges(a.asNode1(), b.asNode1())
or
// Edge is in Config2 graph
DataFlow2::PathGraph::edges(a.asNode2(), b.asNode2())
}
/**
* DEPRECATED: Use flow state instead
*
* Holds if `n` is a node in the graph of data flow path explanations.
*/
deprecated query predicate nodes(CustomPathNode n, string key, string val) {
// Node is in Config1 graph
DataFlow::PathGraph::nodes(n.asNode1(), key, val)
or
// Node is in Config2 graph
DataFlow2::PathGraph::nodes(n.asNode2(), key, val)
}

View File

@@ -1,14 +0,0 @@
/** DEPRECATED. Import `CleartextLoggingQuery` instead. */
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.BarrierGuards
private import semmle.python.dataflow.new.SensitiveDataSources
/** DEPRECATED. Import `CleartextLoggingQuery` instead. */
deprecated module CleartextLogging {
import CleartextLoggingQuery // ignore-query-import
}

View File

@@ -1,14 +0,0 @@
/** DEPRECATED. Import `CleartextStorageQuery` instead. */
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.BarrierGuards
private import semmle.python.dataflow.new.SensitiveDataSources
/** DEPRECATED. Import `CleartextStorageQuery` instead. */
deprecated module CleartextStorage {
import CleartextStorageQuery // ignore-query-import
}

View File

@@ -1,13 +0,0 @@
/** DEPRECATED. Import `CodeInjectionQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `CodeInjectionQuery` instead. */
deprecated module CodeInjection {
import CodeInjectionQuery // ignore-query-import
}
/** DEPRECATED. Import `CodeInjectionQuery` instead. */
deprecated class CodeInjectionConfiguration = CodeInjection::Configuration;

View File

@@ -1,13 +0,0 @@
/** DEPRECATED. Import `CommandInjectionQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `CommandInjectionQuery` instead. */
deprecated module CommandInjection {
import CommandInjectionQuery // ignore-query-import
}
/** DEPRECATED. Import `CommandInjectionQuery` instead. */
deprecated class CommandInjectionConfiguration = CommandInjection::Configuration;

View File

@@ -1,12 +0,0 @@
/** DEPRECATED. Import `LdapInjectionQuery` instead. */
import python
import semmle.python.Concepts
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.RemoteFlowSources
/** DEPRECATED. Import `LdapInjectionQuery` instead. */
deprecated module LdapInjection {
import LdapInjectionQuery // ignore-query-import
}

View File

@@ -1,10 +0,0 @@
/** DEPRECATED. Import `LogInjectionQuery` instead. */
import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `LogInjectionQuery` instead. */
deprecated module LogInjection {
import LogInjectionQuery // ignore-query-import
}

View File

@@ -1,133 +0,0 @@
/** DEPRECATED. Import `PathInjectionQuery` instead. */
private import python
private import semmle.python.Concepts
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `PathInjectionQuery` instead. */
deprecated module PathInjection {
import PathInjectionQuery // ignore-query-import
}
// ---------------------------------------------------------------------------
// Old, deprecated code
// ---------------------------------------------------------------------------
private import semmle.python.dataflow.new.DataFlow2
private import semmle.python.dataflow.new.TaintTracking2
private import ChainedConfigs12
import PathInjectionCustomizations::PathInjection
// ---------------------------------------------------------------------------
// Case 1. The path is never normalized.
// ---------------------------------------------------------------------------
/**
* DEPRECATED: Import `PathInjectionQuery` instead.
*
* Configuration to find paths from sources to sinks that contain no normalization.
*/
deprecated class PathNotNormalizedConfiguration extends TaintTracking::Configuration {
PathNotNormalizedConfiguration() { this = "PathNotNormalizedConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) {
node instanceof Sanitizer
or
node instanceof Path::PathNormalization
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
/**
* DEPRECATED: Import `PathInjectionQuery` instead.
*
* Holds if there is a path injection from source to sink, where the (python) path is
* not normalized.
*/
deprecated predicate pathNotNormalized(CustomPathNode source, CustomPathNode sink) {
any(PathNotNormalizedConfiguration config).hasFlowPath(source.asNode1(), sink.asNode1())
}
// ---------------------------------------------------------------------------
// Case 2. The path is normalized at least once, but never checked afterwards.
// ---------------------------------------------------------------------------
/**
* DEPRECATED: Import `PathInjectionQuery` instead.
*
* Configuration to find paths from sources to normalizations that contain no prior normalizations.
*/
deprecated class FirstNormalizationConfiguration extends TaintTracking::Configuration {
FirstNormalizationConfiguration() { this = "FirstNormalizationConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof Source }
override predicate isSink(DataFlow::Node sink) { sink instanceof Path::PathNormalization }
override predicate isSanitizer(DataFlow::Node node) { node instanceof Sanitizer }
override predicate isSanitizerOut(DataFlow::Node node) { node instanceof Path::PathNormalization }
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
/**
* DEPRECATED: Import `PathInjectionQuery` instead.
*
* Configuration to find paths from normalizations to sinks that do not go through a check.
*/
deprecated class NormalizedPathNotCheckedConfiguration extends TaintTracking2::Configuration {
NormalizedPathNotCheckedConfiguration() { this = "NormalizedPathNotCheckedConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof Path::PathNormalization }
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
override predicate isSanitizer(DataFlow::Node node) {
node instanceof Path::SafeAccessCheck
or
node instanceof Sanitizer
}
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
guard instanceof SanitizerGuard
}
}
/**
* DEPRECATED: Import `PathInjectionQuery` instead.
*
* Holds if there is a path injection from source to sink, where the (python) path is
* normalized at least once, but never checked afterwards.
*/
deprecated predicate pathNotCheckedAfterNormalization(CustomPathNode source, CustomPathNode sink) {
exists(
FirstNormalizationConfiguration config, DataFlow::PathNode mid1, DataFlow2::PathNode mid2,
NormalizedPathNotCheckedConfiguration config2
|
config.hasFlowPath(source.asNode1(), mid1) and
config2.hasFlowPath(mid2, sink.asNode2()) and
mid1.getNode().asCfgNode() = mid2.getNode().asCfgNode()
)
}
// ---------------------------------------------------------------------------
// Query: Either case 1 or case 2.
// ---------------------------------------------------------------------------
/**
* DEPRECATED: Import `PathInjectionQuery` instead.
*
* Holds if there is a path injection from source to sink
*/
deprecated predicate pathInjection(CustomPathNode source, CustomPathNode sink) {
pathNotNormalized(source, sink)
or
pathNotCheckedAfterNormalization(source, sink)
}

View File

@@ -1,10 +0,0 @@
/** DEPRECATED. Import `PolynomialReDoSQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `PolynomialReDoSQuery` instead. */
deprecated module PolynomialReDoS {
import PolynomialReDoSQuery // ignore-query-import
}

View File

@@ -1,16 +0,0 @@
/** DEPRECATED. Import `ReflectedXSSQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `ReflectedXSSQuery` instead. */
deprecated module ReflectedXss {
import ReflectedXssQuery // ignore-query-import
}
/** DEPRECATED. Import `ReflectedXSSQuery` instead. */
deprecated module ReflectedXSS = ReflectedXss;
/** DEPRECATED. Import `ReflectedXSSQuery` instead. */
deprecated class ReflectedXssConfiguration = ReflectedXss::Configuration;

View File

@@ -76,6 +76,3 @@ module ReflectedXss {
*/
class StringConstCompareAsSanitizerGuard extends Sanitizer, StringConstCompareBarrier { }
}
/** DEPRECATED: Alias for ReflectedXss */
deprecated module ReflectedXSS = ReflectedXss;

View File

@@ -1,10 +0,0 @@
/** DEPRECATED. Import `RegexInjectionQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `RegexInjectionQuery` instead. */
deprecated module RegexInjection {
import RegexInjectionQuery // ignore-query-import
}

View File

@@ -1,25 +0,0 @@
/** DEPRECATED. Import `ServerSideRequestForgeryQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.Concepts
import ServerSideRequestForgeryQuery as ServerSideRequestForgeryQuery // ignore-query-import
/** DEPRECATED. Import `ServerSideRequestForgeryQuery` instead. */
deprecated module FullServerSideRequestForgery {
import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery
class Configuration = ServerSideRequestForgeryQuery::FullServerSideRequestForgeryConfiguration;
}
/** DEPRECATED. Import `ServerSideRequestForgeryQuery` instead. */
deprecated predicate fullyControlledRequest =
ServerSideRequestForgeryQuery::fullyControlledRequest/1;
/** DEPRECATED. Import `ServerSideRequestForgeryQuery` instead. */
deprecated module PartialServerSideRequestForgery {
import ServerSideRequestForgeryCustomizations::ServerSideRequestForgery
class Configuration = ServerSideRequestForgeryQuery::PartialServerSideRequestForgeryConfiguration;
}

View File

@@ -1,16 +0,0 @@
/** DEPRECATED. Import `SqlInjectionQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `SqlInjectionQuery` instead. */
deprecated module SqlInjection {
import SqlInjectionQuery // ignore-query-import
}
/** DEPRECATED. Import `SqlInjectionQuery` instead. */
deprecated class SqlInjectionConfiguration = SqlInjection::Configuration;
/** DEPRECATED. Import `SqlInjectionQuery` instead. */
deprecated class SQLInjectionConfiguration = SqlInjectionConfiguration;

View File

@@ -1,13 +0,0 @@
/** DEPRECATED. Import `StackTraceExposureQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `StackTraceExposureQuery` instead. */
deprecated module StackTraceExposure {
import StackTraceExposureQuery // ignore-query-import
}
/** DEPRECATED. Import `StackTraceExposureQuery` instead. */
deprecated class StackTraceExposureConfiguration = StackTraceExposure::Configuration;

View File

@@ -1,13 +0,0 @@
/** DEPRECATED. Import `UnsafeDeserializationQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `UnsafeDeserializationQuery` instead. */
deprecated module UnsafeDeserialization {
import UnsafeDeserializationQuery // ignore-query-import
}
/** DEPRECATED. Import `UnsafeDeserializationQuery` instead. */
deprecated class UnsafeDeserializationConfiguration = UnsafeDeserialization::Configuration;

View File

@@ -1,13 +0,0 @@
/** DEPRECATED. Import `UrlRedirectQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `UrlRedirectQuery` instead. */
deprecated module UrlRedirect {
import UrlRedirectQuery // ignore-query-import
}
/** DEPRECATED. Import `UrlRedirectQuery` instead. */
deprecated class UrlRedirectConfiguration = UrlRedirect::Configuration;

View File

@@ -1,19 +0,0 @@
/** DEPRECATED. Import `WeakSensitiveDataHashingQuery` instead. */
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.BarrierGuards
private import semmle.python.dataflow.new.SensitiveDataSources
/** DEPRECATED. Import `WeakSensitiveDataHashingQuery` instead. */
deprecated module NormalHashFunction {
import WeakSensitiveDataHashingQuery::NormalHashFunction // ignore-query-import
}
/** DEPRECATED. Import `WeakSensitiveDataHashingQuery` instead. */
deprecated module ComputationallyExpensiveHashFunction {
import WeakSensitiveDataHashingQuery::ComputationallyExpensiveHashFunction // ignore-query-import
}

View File

@@ -1,10 +0,0 @@
/** DEPRECATED. Import `XpathInjectionQuery` instead. */
private import python
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
/** DEPRECATED. Import `XpathInjectionQuery` instead. */
deprecated module XpathInjection {
import XpathInjectionQuery // ignore-query-import
}

View File

@@ -1,9 +0,0 @@
import python
import semmle.python.security.strings.Basic
/** Assume that taint flows from argument to result for *any* call */
deprecated class AnyCallStringFlow extends DataFlowExtension::DataFlowNode {
AnyCallStringFlow() { any(CallNode call).getAnArg() = this }
override ControlFlowNode getASuccessorNode() { result.(CallNode).getAnArg() = this }
}

View File

@@ -1,263 +0,0 @@
/**
* Provides class and predicates to track external data that
* may represent malicious OS commands.
*
* This module is intended to be imported into a taint-tracking query
* to extend `TaintKind` and `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
/** Abstract taint sink that is potentially vulnerable to malicious shell commands. */
abstract deprecated class CommandSink extends TaintSink { }
deprecated private ModuleObject osOrPopenModule() { result.getName() = ["os", "popen2"] }
deprecated private Object makeOsCall() {
exists(string name | result = ModuleObject::named("subprocess").attr(name) |
name = ["Popen", "call", "check_call", "check_output", "run"]
)
}
/**Special case for first element in sequence. */
deprecated class FirstElementKind extends TaintKind {
FirstElementKind() { this = "sequence[" + any(ExternalStringKind key) + "][0]" }
override string repr() { result = "first item in sequence of " + this.getItem().repr() }
/** Gets the taint kind for item in this sequence. */
ExternalStringKind getItem() { this = "sequence[" + result + "][0]" }
}
deprecated class FirstElementFlow extends DataFlowExtension::DataFlowNode {
FirstElementFlow() { this = any(SequenceNode s).getElement(0) }
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
result.(SequenceNode).getElement(0) = this and tokind.(FirstElementKind).getItem() = fromkind
}
}
/**
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `subprocess.call(shell=vuln)` and similar calls.
*/
deprecated class ShellCommand extends CommandSink {
override string toString() { result = "shell command" }
ShellCommand() {
exists(CallNode call, Object istrue |
call.getFunction().refersTo(makeOsCall()) and
call.getAnArg() = this and
call.getArgByName("shell").refersTo(istrue) and
istrue.booleanValue() = true
)
or
exists(CallNode call, string name |
call.getAnArg() = this and
call.getFunction().refersTo(osOrPopenModule().attr(name))
|
name = ["system", "popen"] or
name.matches("popen_")
)
or
exists(CallNode call |
call.getAnArg() = this and
call.getFunction().refersTo(ModuleObject::named("commands"))
)
}
override predicate sinks(TaintKind kind) {
/* Tainted string command */
kind instanceof ExternalStringKind
or
/* List (or tuple) containing a tainted string command */
kind instanceof ExternalStringSequenceKind
}
}
/**
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `subprocess.call(vuln, ...)` and similar calls.
*/
deprecated class OsCommandFirstArgument extends CommandSink {
override string toString() { result = "OS command first argument" }
OsCommandFirstArgument() {
not this instanceof ShellCommand and
exists(CallNode call |
call.getFunction().refersTo(makeOsCall()) and
call.getArg(0) = this
)
}
override predicate sinks(TaintKind kind) {
/* Tainted string command */
kind instanceof ExternalStringKind
or
/* List (or tuple) whose first element is tainted */
kind instanceof FirstElementKind
}
}
// -------------------------------------------------------------------------- //
// Modeling of the 'invoke' package and 'fabric' package (v 2.x)
//
// Since fabric build so closely upon invoke, we model them together to avoid
// duplication
// -------------------------------------------------------------------------- //
/**
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `invoke.run(vuln, ...)` and similar calls.
*/
deprecated class InvokeRun extends CommandSink {
InvokeRun() {
this = Value::named("invoke.run").(FunctionValue).getArgumentForCall(_, 0)
or
this = Value::named("invoke.sudo").(FunctionValue).getArgumentForCall(_, 0)
}
override string toString() { result = "InvokeRun" }
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
/**
* Internal TaintKind to track the invoke.Context instance passed to functions
* marked with @invoke.task
*/
deprecated private class InvokeContextArg extends TaintKind {
InvokeContextArg() { this = "InvokeContextArg" }
}
/** Internal TaintSource to track the context passed to functions marked with @invoke.task */
deprecated private class InvokeContextArgSource extends TaintSource {
InvokeContextArgSource() {
exists(Function f, Expr decorator |
count(f.getADecorator()) = 1 and
(
decorator = f.getADecorator() and not decorator instanceof Call
or
decorator = f.getADecorator().(Call).getFunc()
) and
(
decorator.pointsTo(Value::named("invoke.task"))
or
decorator.pointsTo(Value::named("fabric.task"))
)
|
this.(ControlFlowNode).getNode() = f.getArg(0)
)
}
override predicate isSourceOf(TaintKind kind) { kind instanceof InvokeContextArg }
}
/**
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `invoke.Context().run(vuln, ...)` and similar calls.
*/
deprecated class InvokeContextRun extends CommandSink {
InvokeContextRun() {
exists(CallNode call |
any(InvokeContextArg k).taints(call.getFunction().(AttrNode).getObject("run"))
or
call = Value::named("invoke.Context").(ClassValue).lookup("run").getACall()
or
// fabric.connection.Connection is a subtype of invoke.context.Context
// since fabric.Connection.run has a decorator, it doesn't work with FunctionValue :|
// and `Value::named("fabric.Connection").(ClassValue).lookup("run").getACall()` returned no results,
// so here is the hacky solution that works :\
call.getFunction().(AttrNode).getObject("run").pointsTo().getClass() =
Value::named("fabric.Connection")
|
this = call.getArg(0)
or
this = call.getArgByName("command")
)
}
override string toString() { result = "InvokeContextRun" }
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
/**
* A taint sink that is potentially vulnerable to malicious shell commands.
* The `vuln` in `fabric.Group().run(vuln, ...)` and similar calls.
*/
deprecated class FabricGroupRun extends CommandSink {
FabricGroupRun() {
exists(ClassValue cls |
cls.getASuperType() = Value::named("fabric.Group") and
this = cls.lookup("run").(FunctionValue).getArgumentForCall(_, 1)
)
}
override string toString() { result = "FabricGroupRun" }
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
// -------------------------------------------------------------------------- //
// Modeling of the 'invoke' package and 'fabric' package (v 1.x)
// -------------------------------------------------------------------------- //
deprecated class FabricV1Commands extends CommandSink {
FabricV1Commands() {
// since `run` and `sudo` are decorated, we can't use FunctionValue's :(
exists(CallNode call |
call = Value::named("fabric.api.local").getACall()
or
call = Value::named("fabric.api.run").getACall()
or
call = Value::named("fabric.api.sudo").getACall()
|
this = call.getArg(0)
or
this = call.getArgByName("command")
)
}
override string toString() { result = "FabricV1Commands" }
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
/**
* An extension that propagates taint from the arguments of `fabric.api.execute(func, arg0, arg1, ...)`
* to the parameters of `func`, since this will call `func(arg0, arg1, ...)`.
*/
deprecated class FabricExecuteExtension extends DataFlowExtension::DataFlowNode {
CallNode call;
FabricExecuteExtension() {
call = Value::named("fabric.api.execute").getACall() and
(
this = call.getArg(any(int i | i > 0))
or
this = call.getArgByName(any(string s | not s = "task"))
)
}
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
tokind = fromkind and
exists(CallableValue func |
(
call.getArg(0).pointsTo(func)
or
call.getArgByName("task").pointsTo(func)
) and
exists(int i |
// execute(func, arg0, arg1) => func(arg0, arg1)
this = call.getArg(i) and
result = func.getParameter(i - 1)
)
or
exists(string name |
this = call.getArgByName(name) and
result = func.getParameterByName(name)
)
)
}
}

View File

@@ -1,8 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
/** `pickle.loads(untrusted)` vulnerability. */
abstract deprecated class DeserializationSink extends TaintSink {
bindingset[this]
DeserializationSink() { this = this }
}

View File

@@ -1,29 +0,0 @@
/**
* Provides class and predicates to track external data that
* may represent malicious Python code.
*
* This module is intended to be imported into a taint-tracking query
* to extend `TaintKind` and `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
/**
* A taint sink that represents an argument to exec or eval that is vulnerable to malicious input.
* The `vuln` in `exec(vuln)` or similar.
*/
deprecated class StringEvaluationNode extends TaintSink {
override string toString() { result = "exec or eval" }
StringEvaluationNode() {
exists(Exec exec | exec.getASubExpression().getAFlowNode() = this)
or
Value::named("exec").getACall().getAnArg() = this
or
Value::named("eval").getACall().getAnArg() = this
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}

View File

@@ -1,33 +0,0 @@
/**
* Provides class and predicates to track external data that
* may represent malicious marshals.
*
* This module is intended to be imported into a taint-tracking query
* to extend `TaintKind` and `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.injection.Deserialization
deprecated private FunctionObject marshalLoads() {
result = ModuleObject::named("marshal").attr("loads")
}
/**
* A taint sink that is potentially vulnerable to malicious marshaled objects.
* The `vuln` in `marshal.loads(vuln)`.
*/
deprecated class UnmarshalingNode extends DeserializationSink {
override string toString() { result = "unmarshaling vulnerability" }
UnmarshalingNode() {
exists(CallNode call |
marshalLoads().getACall() = call and
call.getAnArg() = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}

View File

@@ -1,81 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
/**
* Prevents taint flowing through ntpath.normpath()
* NormalizedPath below handles that case.
*/
deprecated class PathSanitizer extends Sanitizer {
PathSanitizer() { this = "path.sanitizer" }
override predicate sanitizingNode(TaintKind taint, ControlFlowNode node) {
taint instanceof ExternalStringKind and
abspath_call(node, _)
}
}
deprecated private FunctionObject abspath() {
exists(ModuleObject os_path | ModuleObject::named("os").attr("path") = os_path |
os_path.attr("abspath") = result
or
os_path.attr("normpath") = result
)
}
/** A path that has been normalized, but not verified to be safe */
deprecated class NormalizedPath extends TaintKind {
NormalizedPath() { this = "normalized.path.injection" }
override string repr() { result = "normalized path" }
}
deprecated private predicate abspath_call(CallNode call, ControlFlowNode arg) {
call.getFunction().refersTo(abspath()) and
arg = call.getArg(0)
}
deprecated class AbsPath extends DataFlowExtension::DataFlowNode {
AbsPath() { abspath_call(_, this) }
override ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) {
abspath_call(result, this) and
tokind instanceof NormalizedPath and
fromkind instanceof ExternalStringKind
}
}
deprecated class NormalizedPathSanitizer extends Sanitizer {
NormalizedPathSanitizer() { this = "normalized.path.sanitizer" }
override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) {
taint instanceof NormalizedPath and
test.getTest().(CallNode).getFunction().(AttrNode).getName() = "startswith" and
test.getSense() = true
}
}
/**
* A taint sink that is vulnerable to malicious paths.
* The `vuln` in `open(vuln)` and similar.
*/
deprecated class OpenNode extends TaintSink {
override string toString() { result = "argument to open()" }
OpenNode() {
exists(CallNode call |
call = Value::named("open").getACall() and
(
call.getArg(0) = this
or
call.getArgByName("file") = this
)
)
}
override predicate sinks(TaintKind kind) {
kind instanceof ExternalStringKind
or
kind instanceof NormalizedPath
}
}

View File

@@ -1,36 +0,0 @@
/**
* Provides class and predicates to track external data that
* may represent malicious pickles.
*
* This module is intended to be imported into a taint-tracking query
* to extend `TaintKind` and `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.injection.Deserialization
deprecated private ModuleObject pickleModule() {
result.getName() = "pickle"
or
result.getName() = "cPickle"
or
result.getName() = "dill"
}
deprecated private FunctionObject pickleLoads() { result = pickleModule().attr("loads") }
/** `pickle.loads(untrusted)` vulnerability. */
deprecated class UnpicklingNode extends DeserializationSink {
override string toString() { result = "unpickling untrusted data" }
UnpicklingNode() {
exists(CallNode call |
pickleLoads().getACall() = call and
call.getAnArg() = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}

View File

@@ -1,6 +0,0 @@
/** DEPRECATED: use semmle.python.security.dataflow.RegexInjection instead. */
private import semmle.python.security.dataflow.RegexInjection as New
/** DEPRECATED: use semmle.python.security.dataflow.RegexInjection instead. */
deprecated module RegexInjection = New::RegexInjection;

View File

@@ -1,6 +0,0 @@
/** DEPRECATED: use semmle.python.security.dataflow.RegexInjectionCustomizations instead. */
private import semmle.python.security.dataflow.RegexInjectionCustomizations as New
/** DEPRECATED: use semmle.python.security.dataflow.RegexInjectionCustomizations instead. */
deprecated module RegexInjection = New::RegexInjection;

View File

@@ -1,83 +0,0 @@
/**
* Provides class and predicates to track external data that
* may represent malicious SQL queries or parts of queries.
*
* This module is intended to be imported into a taint-tracking query
* to extend `TaintKind` and `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.SQL
deprecated private StringObject first_part(ControlFlowNode command) {
command.(BinaryExprNode).getOp() instanceof Add and
command.(BinaryExprNode).getLeft().refersTo(result)
or
exists(CallNode call, SequenceObject seq | call = command |
call = theStrType().lookupAttribute("join") and
call.getArg(0).refersTo(seq) and
seq.getInferredElement(0) = result
)
or
command.(BinaryExprNode).getOp() instanceof Mod and
command.getNode().(StrConst).getLiteralObject() = result
}
/** Holds if `command` appears to be a SQL command string of which `inject` is a part. */
deprecated predicate probable_sql_command(ControlFlowNode command, ControlFlowNode inject) {
exists(string prefix |
inject = command.getAChild*() and
first_part(command).getText().regexpMatch(" *" + prefix + ".*")
|
prefix = "CREATE" or prefix = "SELECT"
)
}
/**
* A taint kind representing a DB cursor.
* This will be overridden to provide specific kinds of DB cursor.
*/
abstract deprecated class DbCursor extends TaintKind {
bindingset[this]
DbCursor() { any() }
string getExecuteMethodName() { result = "execute" }
}
/**
* A part of a string that appears to be a SQL command and is thus
* vulnerable to malicious input.
*/
deprecated class SimpleSqlStringInjection extends SqlInjectionSink {
override string toString() { result = "simple SQL string injection" }
SimpleSqlStringInjection() { probable_sql_command(_, this) }
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
/**
* A taint source representing sources of DB connections.
* This will be overridden to provide specific kinds of DB connection sources.
*/
abstract deprecated class DbConnectionSource extends TaintSource { }
/**
* A taint sink that is vulnerable to malicious SQL queries.
* The `vuln` in `db.connection.execute(vuln)` and similar.
*/
deprecated class DbConnectionExecuteArgument extends SqlInjectionSink {
override string toString() { result = "db.connection.execute" }
DbConnectionExecuteArgument() {
exists(CallNode call, DbCursor cursor, string name |
cursor.taints(call.getFunction().(AttrNode).getObject(name)) and
cursor.getExecuteMethodName() = name and
call.getArg(0) = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}

View File

@@ -1,70 +0,0 @@
/**
* Provides class and predicates to track external data that
* may represent malicious XML objects.
*
* This module is intended to be imported into a taint-tracking query
* to extend `TaintKind` and `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.injection.Deserialization
deprecated private ModuleObject xmlElementTreeModule() {
result.getName() = "xml.etree.ElementTree"
}
deprecated private ModuleObject xmlMiniDomModule() { result.getName() = "xml.dom.minidom" }
deprecated private ModuleObject xmlPullDomModule() { result.getName() = "xml.dom.pulldom" }
deprecated private ModuleObject xmlSaxModule() { result.getName() = "xml.sax" }
deprecated private class ExpatParser extends TaintKind {
ExpatParser() { this = "expat.parser" }
}
deprecated private FunctionObject expatCreateParseFunction() {
result = ModuleObject::named("xml.parsers.expat").attr("ParserCreate")
}
deprecated private class ExpatCreateParser extends TaintSource {
ExpatCreateParser() { expatCreateParseFunction().getACall() = this }
override predicate isSourceOf(TaintKind kind) { kind instanceof ExpatParser }
override string toString() { result = "expat.create.parser" }
}
deprecated private FunctionObject xmlFromString() {
result = xmlElementTreeModule().attr("fromstring")
or
result = xmlMiniDomModule().attr("parseString")
or
result = xmlPullDomModule().attr("parseString")
or
result = xmlSaxModule().attr("parseString")
}
/** A (potentially) malicious XML string. */
deprecated class ExternalXmlString extends ExternalStringKind {
ExternalXmlString() { this = "external xml encoded object" }
}
/**
* A call to an XML library function that is potentially vulnerable to a
* specially crafted XML string.
*/
deprecated class XmlLoadNode extends DeserializationSink {
override string toString() { result = "xml.load vulnerability" }
XmlLoadNode() {
exists(CallNode call | call.getAnArg() = this |
xmlFromString().getACall() = call or
any(ExpatParser parser).taints(call.getFunction().(AttrNode).getObject("Parse"))
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalXmlString }
}

View File

@@ -1,28 +0,0 @@
/**
* Provides class and predicates to track external data that
* may represent malicious yaml-encoded objects.
*
* This module is intended to be imported into a taint-tracking query
* to extend `TaintKind` and `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.security.injection.Deserialization
deprecated private FunctionObject yamlLoad() { result = ModuleObject::named("yaml").attr("load") }
/** `yaml.load(untrusted)` vulnerability. */
deprecated class YamlLoadNode extends DeserializationSink {
override string toString() { result = "yaml.load vulnerability" }
YamlLoadNode() {
exists(CallNode call |
yamlLoad().getACall() = call and
call.getAnArg() = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}

View File

@@ -14,7 +14,6 @@ import python
private import semmle.python.pointsto.PointsTo
private import semmle.python.pointsto.PointsToContext
private import semmle.python.objects.TObject
private import semmle.python.web.HttpConstants
/* Make ObjectInternal visible to save extra imports in user code */
import semmle.python.objects.ObjectInternal
@@ -52,30 +51,6 @@ class RangeIterationVariableFact extends PointsToExtension {
}
}
/* bottle module route constants */
deprecated class BottleRoutePointToExtension extends PointsToExtension {
string name;
BottleRoutePointToExtension() {
exists(DefinitionNode defn |
defn.getScope().(Module).getName() = "bottle" and
this = defn.getValue() and
name = defn.(NameNode).getId()
|
name = "route" or
name = httpVerbLower()
)
}
override predicate pointsTo(Context context, ObjectInternal value, ControlFlowNode origin) {
context.isImport() and
exists(CfgOrigin orig |
Module::named("bottle").attr("Bottle").(ClassObjectInternal).attribute(name, value, orig) and
origin = orig.asCfgNodeOrHere(this)
)
}
}
/* Python 3.6+ regex module constants */
string short_flag(string flag) {
flag in ["ASCII", "IGNORECASE", "LOCALE", "UNICODE", "MULTILINE", "TEMPLATE"] and

View File

@@ -1,2 +0,0 @@
import semmle.python.web.client.StdLib
import semmle.python.web.client.Requests

View File

@@ -1,7 +0,0 @@
import python
import semmle.python.security.strings.Basic
import semmle.python.web.django.Redirect
import semmle.python.web.flask.Redirect
import semmle.python.web.tornado.Redirect
import semmle.python.web.pyramid.Redirect
import semmle.python.web.bottle.Redirect

View File

@@ -1,10 +0,0 @@
import semmle.python.web.django.Response
import semmle.python.web.flask.Response
import semmle.python.web.pyramid.Response
import semmle.python.web.tornado.Response
import semmle.python.web.twisted.Response
import semmle.python.web.bottle.Response
import semmle.python.web.turbogears.Response
import semmle.python.web.falcon.Response
import semmle.python.web.cherrypy.Response
import semmle.python.web.stdlib.Response

View File

@@ -1,28 +0,0 @@
/**
* Provides class representing the `bottle.redirect` function.
* This module is intended to be imported into a taint-tracking query
* to extend `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.bottle.General
deprecated FunctionValue bottle_redirect() { result = theBottleModule().attr("redirect") }
/**
* An argument to the `bottle.redirect` function.
*/
deprecated class BottleRedirect extends TaintSink {
override string toString() { result = "bottle.redirect" }
BottleRedirect() {
exists(CallNode call |
bottle_redirect().getACall() = call and
this = call.getAnArg()
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}

View File

@@ -1,52 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.web.Http
import semmle.python.web.bottle.General
/**
* A bottle.Response object
* This isn't really a "taint", but we use the value tracking machinery to
* track the flow of response objects.
*/
deprecated class BottleResponse extends TaintKind {
BottleResponse() { this = "bottle.response" }
}
deprecated private Value theBottleResponseObject() { result = theBottleModule().attr("response") }
deprecated class BottleResponseBodyAssignment extends HttpResponseTaintSink {
BottleResponseBodyAssignment() {
exists(DefinitionNode lhs |
lhs.getValue() = this and
lhs.(AttrNode).getObject("body").pointsTo(theBottleResponseObject())
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}
deprecated class BottleHandlerFunctionResult extends HttpResponseTaintSink {
BottleHandlerFunctionResult() {
exists(BottleRoute route, Return ret |
ret.getScope() = route.getFunction() and
ret.getValue().getAFlowNode() = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
override string toString() { result = "bottle handler function result" }
}
deprecated class BottleCookieSet extends CookieSet, CallNode {
BottleCookieSet() {
any(BottleResponse r).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
}
override string toString() { result = CallNode.super.toString() }
override ControlFlowNode getKey() { result = this.getArg(0) }
override ControlFlowNode getValue() { result = this.getArg(1) }
}

View File

@@ -1,18 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Untrusted
import semmle.python.web.Http
import semmle.python.web.cherrypy.General
deprecated class CherryPyExposedFunctionResult extends HttpResponseTaintSink {
CherryPyExposedFunctionResult() {
exists(Return ret |
ret.getScope() instanceof CherryPyExposedFunction and
ret.getValue().getAFlowNode() = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
override string toString() { result = "cherrypy handler function result" }
}

View File

@@ -1,22 +0,0 @@
/**
* Modeling outgoing HTTP requests using the `requests` package
* https://pypi.org/project/requests/
*/
import python
private import semmle.python.web.Http
deprecated class RequestsHttpRequest extends Client::HttpRequest, CallNode {
CallableValue func;
string method;
RequestsHttpRequest() {
method = httpVerbLower() and
func = Module::named("requests").attr(method) and
this = func.getACall()
}
override ControlFlowNode getAUrlPart() { result = func.getNamedArgumentForCall(this, "url") }
override string getMethodUpper() { result = method.toUpperCase() }
}

View File

@@ -1,55 +0,0 @@
import python
private import semmle.python.web.Http
deprecated ClassValue httpConnectionClass() {
// Python 2
result = Value::named("httplib.HTTPConnection")
or
result = Value::named("httplib.HTTPSConnection")
or
// Python 3
result = Value::named("http.client.HTTPConnection")
or
result = Value::named("http.client.HTTPSConnection")
or
// six
result = Value::named("six.moves.http_client.HTTPConnection")
or
result = Value::named("six.moves.http_client.HTTPSConnection")
}
deprecated class HttpConnectionHttpRequest extends Client::HttpRequest, CallNode {
CallNode constructor_call;
CallableValue func;
HttpConnectionHttpRequest() {
exists(ClassValue cls, AttrNode call_origin, Value constructor_call_value |
cls = httpConnectionClass() and
func = cls.lookup("request") and
this = func.getACall() and
// since you can do `r = conn.request; r('GET', path)`, we need to find the origin
this.getFunction().pointsTo(_, _, call_origin) and
// Since HTTPSConnection is a subtype of HTTPConnection, up until this point, `cls` could be either class,
// because `HTTPSConnection.request == HTTPConnection.request`. To avoid generating 2 results, we filter
// on the actual class used as the constructor
call_origin.getObject().pointsTo(_, constructor_call_value, constructor_call) and
cls = constructor_call_value.getClass() and
constructor_call = cls.getACall()
)
}
override ControlFlowNode getAUrlPart() {
result = func.getNamedArgumentForCall(this, "url")
or
result = constructor_call.getArg(0)
or
result = constructor_call.getArgByName("host")
}
override string getMethodUpper() {
exists(string method |
result = method.toUpperCase() and
func.getNamedArgumentForCall(this, "method").pointsTo(Value::forString(method))
)
}
}

View File

@@ -1,50 +0,0 @@
import python
import semmle.python.security.injection.Sql
/**
* A taint kind representing a django cursor object.
*/
deprecated class DjangoDbCursor extends DbCursor {
DjangoDbCursor() { this = "django.db.connection.cursor" }
}
deprecated private Value theDjangoConnectionObject() {
result = Value::named("django.db.connection")
}
/**
* A kind of taint source representing sources of django cursor objects.
*/
deprecated class DjangoDbCursorSource extends DbConnectionSource {
DjangoDbCursorSource() {
exists(AttrNode cursor |
this.(CallNode).getFunction() = cursor and
cursor.getObject("cursor").pointsTo(theDjangoConnectionObject())
)
}
override string toString() { result = "django.db.connection.cursor" }
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbCursor }
}
deprecated ClassValue theDjangoRawSqlClass() {
result = Value::named("django.db.models.expressions.RawSQL")
}
/**
* A sink of taint on calls to `django.db.models.expressions.RawSQL`. This
* allows arbitrary SQL statements to be executed, which is a security risk.
*/
deprecated class DjangoRawSqlSink extends SqlInjectionSink {
DjangoRawSqlSink() {
exists(CallNode call |
call = theDjangoRawSqlClass().getACall() and
this = call.getArg(0)
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
override string toString() { result = "django.db.models.expressions.RawSQL(sink,...)" }
}

View File

@@ -1,69 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.Http
import semmle.python.security.injection.Sql
/** A django model class */
deprecated class DjangoModel extends ClassValue {
DjangoModel() { Value::named("django.db.models.Model") = this.getASuperType() }
}
/** A "taint" for django database tables */
deprecated class DjangoDbTableObjects extends TaintKind {
DjangoDbTableObjects() { this = "django.db.models.Model.objects" }
override TaintKind getTaintOfMethodResult(string name) {
result = this and
name in [
"filter", "exclude", "none", "all", "union", "intersection", "difference", "select_related",
"prefetch_related", "extra", "defer", "only", "annotate", "using", "select_for_update",
"raw", "order_by", "reverse", "distinct", "values", "values_list", "dates", "datetimes"
]
}
}
/** Django model objects, which are sources of django database table "taint" */
deprecated class DjangoModelObjects extends TaintSource {
DjangoModelObjects() {
this.(AttrNode).isLoad() and this.(AttrNode).getObject("objects").pointsTo(any(DjangoModel m))
}
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoDbTableObjects }
override string toString() { result = "django.db.models.Model.objects" }
}
/**
* A call to the `raw` method on a django model. This allows a raw SQL query
* to be sent to the database, which is a security risk.
*/
deprecated class DjangoModelRawCall extends SqlInjectionSink {
DjangoModelRawCall() {
exists(CallNode raw_call, ControlFlowNode queryset | this = raw_call.getArg(0) |
raw_call.getFunction().(AttrNode).getObject("raw") = queryset and
any(DjangoDbTableObjects objs).taints(queryset)
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
override string toString() { result = "django.models.QuerySet.raw(sink,...)" }
}
/**
* A call to the `extra` method on a django model. This allows a raw SQL query
* to be sent to the database, which is a security risk.
*/
deprecated class DjangoModelExtraCall extends SqlInjectionSink {
DjangoModelExtraCall() {
exists(CallNode extra_call, ControlFlowNode queryset | this = extra_call.getArg(0) |
extra_call.getFunction().(AttrNode).getObject("extra") = queryset and
any(DjangoDbTableObjects objs).taints(queryset)
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
override string toString() { result = "django.models.QuerySet.extra(sink,...)" }
}

View File

@@ -1,37 +0,0 @@
/**
* Provides class representing the `django.redirect` function.
* This module is intended to be imported into a taint-tracking query
* to extend `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
private import semmle.python.web.django.Shared
private import semmle.python.web.Http
/**
* The URL argument for a call to the `django.shortcuts.redirect` function.
*/
deprecated class DjangoShortcutsRedirectSink extends HttpRedirectTaintSink {
override string toString() { result = "DjangoShortcutsRedirectSink" }
DjangoShortcutsRedirectSink() {
this = Value::named("django.shortcuts.redirect").(FunctionValue).getArgumentForCall(_, 0)
}
}
/**
* The URL argument when instantiating a Django Redirect Response.
*/
deprecated class DjangoRedirectResponseSink extends HttpRedirectTaintSink {
DjangoRedirectResponseSink() {
exists(CallNode call | call = any(DjangoRedirectResponseClass cls).getACall() |
this = call.getArg(0)
or
this = call.getArgByName("redirect_to")
)
}
override string toString() { result = "DjangoRedirectResponseSink" }
}

View File

@@ -1,79 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
private import semmle.python.web.django.Shared
private import semmle.python.web.Http
/** INTERNAL class used for tracking a django response object. */
deprecated private class DjangoResponseKind extends TaintKind {
DjangoResponseKind() { this = "django.response.HttpResponse" }
}
/** INTERNAL taint-source used for tracking a django response object. */
deprecated private class DjangoResponseSource extends TaintSource {
DjangoResponseSource() { exists(DjangoContentResponseClass cls | cls.getACall() = this) }
override predicate isSourceOf(TaintKind kind) { kind instanceof DjangoResponseKind }
override string toString() { result = "django.http.response.HttpResponse" }
}
/** A write to a django response, which is vulnerable to external data (xss) */
deprecated class DjangoResponseWrite extends HttpResponseTaintSink {
DjangoResponseWrite() {
exists(AttrNode meth, CallNode call |
call.getFunction() = meth and
any(DjangoResponseKind response).taints(meth.getObject("write")) and
this = call.getArg(0)
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
override string toString() { result = "django.Response.write(...)" }
}
/**
* An argument to initialization of a django response.
*/
deprecated class DjangoResponseContent extends HttpResponseTaintSink {
DjangoContentResponseClass cls;
CallNode call;
DjangoResponseContent() {
call = cls.getACall() and
this = cls.getContentArg(call)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
override string toString() { result = "django.Response(...)" }
}
/**
* An argument to initialization of a django response, which is vulnerable to external data (XSS).
*/
deprecated class DjangoResponseContentXSSVulnerable extends DjangoResponseContent {
override DjangoXSSVulnerableResponseClass cls;
DjangoResponseContentXSSVulnerable() {
not exists(cls.getContentTypeArg(call))
or
exists(StringValue s |
cls.getContentTypeArg(call).pointsTo(s) and
s.getText().matches("text/html%")
)
}
}
deprecated class DjangoCookieSet extends CookieSet, CallNode {
DjangoCookieSet() {
any(DjangoResponseKind r).taints(this.getFunction().(AttrNode).getObject("set_cookie"))
}
override string toString() { result = CallNode.super.toString() }
override ControlFlowNode getKey() { result = this.getArg(0) }
override ControlFlowNode getValue() { result = this.getArg(1) }
}

View File

@@ -1,6 +0,0 @@
import python
/*
* Sanitizers
* No django sanitizers implemented yet.
*/

View File

@@ -1,72 +0,0 @@
import python
/** A class that is a Django Redirect Response (subclass of `django.http.HttpResponseRedirectBase`). */
deprecated class DjangoRedirectResponseClass extends ClassValue {
DjangoRedirectResponseClass() {
exists(ClassValue redirect_base |
// version 1.x
redirect_base = Value::named("django.http.response.HttpResponseRedirectBase")
or
// version 2.x and 3.x
redirect_base = Value::named("django.http.HttpResponseRedirectBase")
|
this.getASuperType() = redirect_base
)
}
}
/**
* A class that is a Django Response, which can contain content.
* A subclass of `django.http.HttpResponse` that is not a `DjangoRedirectResponseClass`.
*/
deprecated class DjangoContentResponseClass extends ClassValue {
ClassValue base;
DjangoContentResponseClass() {
(
// version 1.x
base = Value::named("django.http.response.HttpResponse")
or
// version 2.x and 3.x
// https://docs.djangoproject.com/en/2.2/ref/request-response/#httpresponse-objects
base = Value::named("django.http.HttpResponse")
) and
this.getASuperType() = base
}
// The reason these two methods are defined in this class (and not in the Sink
// definition that uses this class), is that if we were to add support for
// `django.http.response.HttpResponseNotAllowed` it would make much more sense to add
// the custom logic in this class (or subclass), than to handle all of it in the sink
// definition.
/** Gets the `content` argument of a `call` to the constructor */
ControlFlowNode getContentArg(CallNode call) { none() }
/** Gets the `content_type` argument of a `call` to the constructor */
ControlFlowNode getContentTypeArg(CallNode call) { none() }
}
/** A class that is a Django Response, and is vulnerable to XSS. */
deprecated class DjangoXSSVulnerableResponseClass extends DjangoContentResponseClass {
DjangoXSSVulnerableResponseClass() {
// We want to avoid FPs on subclasses that are not exposed to XSS, for example `JsonResponse`.
// The easiest way is to disregard any subclass that has a special `__init__` method.
// It's not guaranteed to remove all FPs, or not to generate FNs, but compared to our
// previous implementation that would treat 0-th argument to _any_ subclass as a sink,
// this gets us much closer to reality.
this.lookup("__init__") = base.lookup("__init__") and
not this instanceof DjangoRedirectResponseClass
}
override ControlFlowNode getContentArg(CallNode call) {
result = call.getArg(0)
or
result = call.getArgByName("content")
}
override ControlFlowNode getContentTypeArg(CallNode call) {
result = call.getArg(1)
or
result = call.getArgByName("content_type")
}
}

View File

@@ -1,28 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.web.Http
import semmle.python.web.falcon.General
/** https://falcon.readthedocs.io/en/stable/api/request_and_response.html */
deprecated class FalconResponse extends TaintKind {
FalconResponse() { this = "falcon.response" }
}
/** Only used internally to track the response parameter */
deprecated private class FalconResponseParameter extends TaintSource {
FalconResponseParameter() {
exists(FalconHandlerFunction f | f.getResponse() = this.(ControlFlowNode).getNode())
}
override predicate isSourceOf(TaintKind k) { k instanceof FalconResponse }
}
deprecated class FalconResponseBodySink extends HttpResponseTaintSink {
FalconResponseBodySink() {
exists(AttrNode attr | any(FalconResponse f).taints(attr.getObject("body")) |
attr.(DefinitionNode).getValue() = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}

View File

@@ -1,26 +0,0 @@
/**
* Provides class representing the `flask.redirect` function.
* This module is intended to be imported into a taint-tracking query
* to extend `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.flask.General
deprecated FunctionValue flask_redirect() { result = Value::named("flask.redirect") }
/**
* Represents an argument to the `flask.redirect` function.
*/
deprecated class FlaskRedirect extends HttpRedirectTaintSink {
override string toString() { result = "flask.redirect" }
FlaskRedirect() {
exists(CallNode call |
flask_redirect().getACall() = call and
this = call.getAnArg()
)
}
}

View File

@@ -1,33 +0,0 @@
/**
* Provides class representing the `pyramid.redirect` function.
* This module is intended to be imported into a taint-tracking query
* to extend `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.Http
deprecated private ClassValue redirectClass() {
exists(ModuleValue ex | ex.getName() = "pyramid.httpexceptions" |
ex.attr("HTTPFound") = result
or
ex.attr("HTTPTemporaryRedirect") = result
)
}
/**
* Represents an argument to the `tornado.redirect` function.
*/
deprecated class PyramidRedirect extends HttpRedirectTaintSink {
override string toString() { result = "pyramid.redirect" }
PyramidRedirect() {
exists(CallNode call | call.getFunction().pointsTo(redirectClass()) |
call.getArg(0) = this
or
call.getArgByName("location") = this
)
}
}

View File

@@ -1,37 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.Http
private import semmle.python.web.pyramid.View
/**
* A pyramid response, which is vulnerable to any sort of
* http response malice.
*/
deprecated class PyramidRoutedResponse extends HttpResponseTaintSink {
PyramidRoutedResponse() {
exists(PythonFunctionValue view |
is_pyramid_view_function(view.getScope()) and
this = view.getAReturnedNode()
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
override string toString() { result = "pyramid.routed.response" }
}
deprecated class PyramidCookieSet extends CookieSet, CallNode {
PyramidCookieSet() {
exists(ControlFlowNode f |
f = this.getFunction().(AttrNode).getObject("set_cookie") and
f.pointsTo().getClass() = Value::named("pyramid.response.Response")
)
}
override string toString() { result = CallNode.super.toString() }
override ControlFlowNode getKey() { result = this.getArg(0) }
override ControlFlowNode getValue() { result = this.getArg(1) }
}

View File

@@ -1,43 +0,0 @@
/**
* Provides the sinks for HTTP servers defined with standard library (stdlib).
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.web.Http
deprecated private predicate is_wfile(AttrNode wfile) {
exists(ClassValue cls |
// Python 2
cls.getABaseType+() = Value::named("BaseHTTPServer.BaseHTTPRequestHandler")
or
// Python 3
cls.getABaseType+() = Value::named("http.server.BaseHTTPRequestHandler")
|
wfile.getObject("wfile").pointsTo().getClass() = cls
)
}
/** Sink for `h.wfile.write` where `h` is an instance of BaseHttpRequestHandler. */
deprecated class StdLibWFileWriteSink extends HttpResponseTaintSink {
StdLibWFileWriteSink() {
exists(CallNode call |
is_wfile(call.getFunction().(AttrNode).getObject("write")) and
call.getArg(0) = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
}
/** Sink for `h.wfile.writelines` where `h` is an instance of BaseHttpRequestHandler. */
deprecated class StdLibWFileWritelinesSink extends HttpResponseTaintSink {
StdLibWFileWritelinesSink() {
exists(CallNode call |
is_wfile(call.getFunction().(AttrNode).getObject("writelines")) and
call.getArg(0) = this
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringSequenceKind }
}

View File

@@ -1,28 +0,0 @@
/**
* Provides class representing the `tornado.redirect` function.
* This module is intended to be imported into a taint-tracking query
* to extend `TaintSink`.
*/
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.Http
import Tornado
/**
* Represents an argument to the `tornado.redirect` function.
*/
deprecated class TornadoHttpRequestHandlerRedirect extends HttpRedirectTaintSink {
override string toString() { result = "tornado.HttpRequestHandler.redirect" }
TornadoHttpRequestHandlerRedirect() {
exists(CallNode call, ControlFlowNode node |
node = call.getFunction().(AttrNode).getObject("redirect") and
isTornadoRequestHandlerInstance(node) and
this = call.getArg(0)
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}

View File

@@ -1,47 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
private import semmle.python.web.Http
import Tornado
deprecated class TornadoConnection extends TaintKind {
TornadoConnection() { this = "tornado.http.connection" }
}
deprecated class TornadoConnectionSource extends TaintSource {
TornadoConnectionSource() {
isTornadoRequestHandlerInstance(this.(AttrNode).getObject("connection"))
}
override string toString() { result = "Tornado http connection source" }
override predicate isSourceOf(TaintKind kind) { kind instanceof TornadoConnection }
}
deprecated class TornadoConnectionWrite extends HttpResponseTaintSink {
override string toString() { result = "tornado.connection.write" }
TornadoConnectionWrite() {
exists(CallNode call, ControlFlowNode conn |
conn = call.getFunction().(AttrNode).getObject("write") and
this = call.getAnArg() and
exists(TornadoConnection tc | tc.taints(conn))
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}
deprecated class TornadoHttpRequestHandlerWrite extends HttpResponseTaintSink {
override string toString() { result = "tornado.HttpRequestHandler.write" }
TornadoHttpRequestHandlerWrite() {
exists(CallNode call, ControlFlowNode node |
node = call.getFunction().(AttrNode).getObject("write") and
this = call.getAnArg() and
isTornadoRequestHandlerInstance(node)
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}

View File

@@ -1,31 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.security.strings.Basic
import semmle.python.web.Http
import TurboGears
deprecated class ControllerMethodReturnValue extends HttpResponseTaintSink {
override string toString() { result = "TurboGears ControllerMethodReturnValue" }
ControllerMethodReturnValue() {
exists(TurboGearsControllerMethod m |
m.getAReturnValueFlowNode() = this and
not m.isTemplated()
)
}
override predicate sinks(TaintKind kind) { kind instanceof StringKind }
}
deprecated class ControllerMethodTemplatedReturnValue extends HttpResponseTaintSink {
override string toString() { result = "TurboGears ControllerMethodTemplatedReturnValue" }
ControllerMethodTemplatedReturnValue() {
exists(TurboGearsControllerMethod m |
m.getAReturnValueFlowNode() = this and
m.isTemplated()
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringDictKind }
}

View File

@@ -1,45 +0,0 @@
import python
import semmle.python.dataflow.TaintTracking
import semmle.python.web.Http
import semmle.python.security.strings.Basic
import Twisted
import Request
deprecated class TwistedResponse extends HttpResponseTaintSink {
TwistedResponse() {
exists(PythonFunctionValue func, string name |
isKnownRequestHandlerMethodName(name) and
name = func.getName() and
func = getTwistedRequestHandlerMethod(name) and
this = func.getAReturnedNode()
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
override string toString() { result = "Twisted response" }
}
/**
* A sink of taint in the form of a "setter" method on a twisted request
* object, which affects the properties of the subsequent response sent to this
* request.
*/
deprecated class TwistedRequestSetter extends HttpResponseTaintSink {
TwistedRequestSetter() {
exists(CallNode call, ControlFlowNode node, string name |
(
name = "setHeader" or
name = "addCookie" or
name = "write"
) and
any(TwistedRequest t).taints(node) and
node = call.getFunction().(AttrNode).getObject(name) and
this = call.getAnArg()
)
}
override predicate sinks(TaintKind kind) { kind instanceof ExternalStringKind }
override string toString() { result = "Twisted request setter" }
}

View File

@@ -33,9 +33,6 @@ class SafeExternalApi extends Unit {
DataFlowPrivate::DataFlowCallable getSafeCallable() { none() }
}
/** DEPRECATED: Alias for SafeExternalApi */
deprecated class SafeExternalAPI = SafeExternalApi;
/** The default set of "safe" external APIs. */
private class DefaultSafeExternalApi extends SafeExternalApi {
override DataFlow::CallCfgNode getSafeCall() {
@@ -170,9 +167,6 @@ class ExternalApiDataNode extends DataFlow::Node {
}
}
/** DEPRECATED: Alias for ExternalApiDataNode */
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
@@ -182,9 +176,6 @@ class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
}
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
/** A node representing untrusted data being passed to an external API. */
class UntrustedExternalApiDataNode extends ExternalApiDataNode {
UntrustedExternalApiDataNode() { any(UntrustedDataToExternalApiConfig c).hasFlow(_, this) }
@@ -195,9 +186,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
}
}
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
/** An external API which is used with untrusted data. */
private newtype TExternalApi =
MkExternalApi(string repr, DataFlowPrivate::ArgumentPosition apos) {
@@ -230,6 +218,3 @@ class ExternalApiUsedWithUntrustedData extends MkExternalApi {
/** Gets a textual representation of this element. */
string toString() { result = repr + " [" + apos + "]" }
}
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;

View File

@@ -13,13 +13,10 @@
*/
import python
import semmle.python.security.Paths
import semmle.python.dataflow.TaintTracking
import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TaintTracking
import semmle.python.filters.Tests
class HardcodedValue extends TaintKind {
HardcodedValue() { this = "hard coded value" }
}
import DataFlow::PathGraph
bindingset[char, fraction]
predicate fewer_characters_than(StrConst str, string char, float fraction) {
@@ -78,31 +75,27 @@ predicate maybeCredential(ControlFlowNode f) {
)
}
class HardcodedValueSource extends TaintSource {
HardcodedValueSource() { maybeCredential(this) }
override predicate isSourceOf(TaintKind kind) { kind instanceof HardcodedValue }
class HardcodedValueSource extends DataFlow::Node {
HardcodedValueSource() { maybeCredential(this.asCfgNode()) }
}
class CredentialSink extends TaintSink {
class CredentialSink extends DataFlow::Node {
CredentialSink() {
exists(string name |
name.regexpMatch(getACredentialRegex()) and
not name.matches("%file")
|
any(FunctionValue func).getNamedArgumentForCall(_, name) = this
any(FunctionValue func).getNamedArgumentForCall(_, name) = this.asCfgNode()
or
exists(Keyword k | k.getArg() = name and k.getValue().getAFlowNode() = this)
exists(Keyword k | k.getArg() = name and k.getValue().getAFlowNode() = this.asCfgNode())
or
exists(CompareNode cmp, NameNode n | n.getId() = name |
cmp.operands(this, any(Eq eq), n)
cmp.operands(this.asCfgNode(), any(Eq eq), n)
or
cmp.operands(n, any(Eq eq), this)
cmp.operands(n, any(Eq eq), this.asCfgNode())
)
)
}
override predicate sinks(TaintKind kind) { kind instanceof HardcodedValue }
}
/**
@@ -118,16 +111,14 @@ private string getACredentialRegex() {
class HardcodedCredentialsConfiguration extends TaintTracking::Configuration {
HardcodedCredentialsConfiguration() { this = "Hardcoded credentials configuration" }
override predicate isSource(TaintTracking::Source source) {
source instanceof HardcodedValueSource
}
override predicate isSource(DataFlow::Node source) { source instanceof HardcodedValueSource }
override predicate isSink(TaintTracking::Sink sink) { sink instanceof CredentialSink }
override predicate isSink(DataFlow::Node sink) { sink instanceof CredentialSink }
}
from HardcodedCredentialsConfiguration config, TaintedPathSource src, TaintedPathSink sink
from HardcodedCredentialsConfiguration config, DataFlow::PathNode src, DataFlow::PathNode sink
where
config.hasFlowPath(src, sink) and
not any(TestScope test).contains(src.getAstNode())
select src.getSource(), src, sink, "This hardcoded value is $@.", sink.getNode(),
not any(TestScope test).contains(src.getNode().asCfgNode().getNode())
select src.getNode(), src, sink, "This hardcoded value is $@.", sink.getNode(),
"used as credentials"

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* The query "Arbitrary file write during archive extraction ("Zip Slip")" (`py/zipslip`) has been renamed to "Arbitrary file access during archive extraction ("Zip Slip")."

View File

@@ -4,16 +4,15 @@
<qhelp>
<overview>
<p>Extracting files from a malicious zip archive without validating that the destination file path
is within the destination directory can cause files outside the destination directory to be
overwritten, due to the possible presence of directory traversal elements (<code>..</code>) in
archive paths.</p>
<p>Extracting files from a malicious zip file, or similar type of archive,
is at risk of directory traversal attacks if filenames from the archive are
not properly validated.</p>
<p>Zip archives contain archive entries representing each file in the archive. These entries
include a file path for the entry, but these file paths are not restricted and may contain
unexpected special elements such as the directory traversal element (<code>..</code>). If these
file paths are used to determine an output file to write the contents of the archive item to, then
the file may be written to an unexpected location. This can result in sensitive information being
file paths are used to create a filesystem path, then a file operation may happen in an
unexpected location. This can result in sensitive information being
revealed or deleted, or an attacker being able to influence behavior by modifying unexpected
files.</p>

View File

@@ -1,8 +1,8 @@
/**
* @name Arbitrary file write during archive extraction ("Zip Slip")
* @description Extracting files from a malicious archive without validating that the
* destination file path is within the destination directory can cause files outside
* the destination directory to be overwritten.
* @name Arbitrary file access during archive extraction ("Zip Slip")
* @description Extracting files from a malicious ZIP file, or similar type of archive, without
* validating that the destination file path is within the destination directory
* can allow an attacker to unexpectedly gain access to resources.
* @kind path-problem
* @id py/zipslip
* @problem.severity error

View File

@@ -5,7 +5,7 @@
* @problem.severity error
* @security-severity 9.3
* @precision high
* @id py/command-injection
* @id py/paramiko-command-injection
* @tags security
* experimental
* external/cwe/cwe-074

View File

@@ -90,9 +90,6 @@ module LdapQuery {
}
}
/** DEPRECATED: Alias for LdapQuery */
deprecated module LDAPQuery = LdapQuery;
/**
* A data-flow node that collect methods executing a LDAP query.
*
@@ -106,9 +103,6 @@ class LdapQuery extends DataFlow::Node instanceof LdapQuery::Range {
DataFlow::Node getQuery() { result = super.getQuery() }
}
/** DEPRECATED: Alias for LdapQuery */
deprecated class LDAPQuery = LdapQuery;
/** Provides classes for modeling LDAP components escape-related APIs. */
module LdapEscape {
/**
@@ -125,9 +119,6 @@ module LdapEscape {
}
}
/** DEPRECATED: Alias for LdapEscape */
deprecated module LDAPEscape = LdapEscape;
/**
* A data-flow node that collects functions escaping LDAP components.
*
@@ -141,9 +132,6 @@ class LdapEscape extends DataFlow::Node instanceof LdapEscape::Range {
DataFlow::Node getAnInput() { result = super.getAnInput() }
}
/** DEPRECATED: Alias for LdapEscape */
deprecated class LDAPEscape = LdapEscape;
/** Provides classes for modeling LDAP bind-related APIs. */
module LdapBind {
/**
@@ -173,9 +161,6 @@ module LdapBind {
}
}
/** DEPRECATED: Alias for LdapBind */
deprecated module LDAPBind = LdapBind;
/**
* A data-flow node that collects methods binding a LDAP connection.
*
@@ -202,9 +187,6 @@ class LdapBind extends DataFlow::Node instanceof LdapBind::Range {
deprecated predicate useSSL() { this.useSsl() }
}
/** DEPRECATED: Alias for LdapBind */
deprecated class LDAPBind = LdapBind;
/** Provides classes for modeling SQL sanitization libraries. */
module SqlEscape {
/**
@@ -221,9 +203,6 @@ module SqlEscape {
}
}
/** DEPRECATED: Alias for SqlEscape */
deprecated module SQLEscape = SqlEscape;
/**
* A data-flow node that collects functions escaping SQL statements.
*
@@ -237,9 +216,6 @@ class SqlEscape extends DataFlow::Node instanceof SqlEscape::Range {
DataFlow::Node getAnInput() { result = super.getAnInput() }
}
/** DEPRECATED: Alias for SqlEscape */
deprecated class SQLEscape = SqlEscape;
/** Provides a class for modeling NoSql execution APIs. */
module NoSqlQuery {
/**
@@ -254,9 +230,6 @@ module NoSqlQuery {
}
}
/** DEPRECATED: Alias for NoSqlQuery */
deprecated module NoSQLQuery = NoSqlQuery;
/**
* A data-flow node that executes NoSQL queries.
*
@@ -268,9 +241,6 @@ class NoSqlQuery extends DataFlow::Node instanceof NoSqlQuery::Range {
DataFlow::Node getQuery() { result = super.getQuery() }
}
/** DEPRECATED: Alias for NoSqlQuery */
deprecated class NoSQLQuery = NoSqlQuery;
/** Provides classes for modeling NoSql sanitization-related APIs. */
module NoSqlSanitizer {
/**
@@ -285,9 +255,6 @@ module NoSqlSanitizer {
}
}
/** DEPRECATED: Alias for NoSqlSanitizer */
deprecated module NoSQLSanitizer = NoSqlSanitizer;
/**
* A data-flow node that collects functions sanitizing NoSQL queries.
*
@@ -299,9 +266,6 @@ class NoSqlSanitizer extends DataFlow::Node instanceof NoSqlSanitizer::Range {
DataFlow::Node getAnInput() { result = super.getAnInput() }
}
/** DEPRECATED: Alias for NoSqlSanitizer */
deprecated class NoSQLSanitizer = NoSqlSanitizer;
/** Provides classes for modeling HTTP Header APIs. */
module HeaderDeclaration {
/**
@@ -450,9 +414,6 @@ module JwtEncoding {
}
}
/** DEPRECATED: Alias for JwtEncoding */
deprecated module JWTEncoding = JwtEncoding;
/**
* A data-flow node that collects methods encoding a JWT token.
*
@@ -481,9 +442,6 @@ class JwtEncoding extends DataFlow::Node instanceof JwtEncoding::Range {
string getAlgorithmString() { result = super.getAlgorithmString() }
}
/** DEPRECATED: Alias for JwtEncoding */
deprecated class JWTEncoding = JwtEncoding;
/** Provides classes for modeling JWT decoding-related APIs. */
module JwtDecoding {
/**
@@ -525,9 +483,6 @@ module JwtDecoding {
}
}
/** DEPRECATED: Alias for JwtDecoding */
deprecated module JWTDecoding = JwtDecoding;
/**
* A data-flow node that collects methods encoding a JWT token.
*
@@ -566,9 +521,6 @@ class JwtDecoding extends DataFlow::Node instanceof JwtDecoding::Range {
predicate verifiesSignature() { super.verifiesSignature() }
}
/** DEPRECATED: Alias for JwtDecoding */
deprecated class JWTDecoding = JwtDecoding;
/** Provides classes for modeling Email APIs. */
module EmailSender {
/**

View File

@@ -29,23 +29,14 @@ class LdapFullHost extends StrConst {
}
}
/** DEPRECATED: Alias for LdapFullHost */
deprecated class LDAPFullHost = LdapFullHost;
class LdapSchema extends StrConst {
LdapSchema() { this.getText().regexpMatch(getSchemaRegex()) }
}
/** DEPRECATED: Alias for LdapSchema */
deprecated class LDAPSchema = LdapSchema;
class LdapPrivateHost extends StrConst {
LdapPrivateHost() { this.getText().regexpMatch(getPrivateHostRegex()) }
}
/** DEPRECATED: Alias for LdapPrivateHost */
deprecated class LDAPPrivateHost = LdapPrivateHost;
predicate concatAndCompareAgainstFullHostRegex(LdapSchema schema, StrConst host) {
not host instanceof LdapPrivateHost and
(schema.getText() + host.getText()).regexpMatch(getFullHostRegex())
@@ -56,9 +47,6 @@ class LdapBothStrings extends BinaryExpr {
LdapBothStrings() { concatAndCompareAgainstFullHostRegex(this.getLeft(), this.getRight()) }
}
/** DEPRECATED: Alias for LdapBothStrings */
deprecated class LDAPBothStrings = LdapBothStrings;
// schema + host
class LdapBothVar extends BinaryExpr {
LdapBothVar() {
@@ -73,9 +61,6 @@ class LdapBothVar extends BinaryExpr {
}
}
/** DEPRECATED: Alias for LdapBothVar */
deprecated class LDAPBothVar = LdapBothVar;
// schema + "somethingon.theinternet.com"
class LdapVarString extends BinaryExpr {
LdapVarString() {
@@ -89,9 +74,6 @@ class LdapVarString extends BinaryExpr {
}
}
/** DEPRECATED: Alias for LdapVarString */
deprecated class LDAPVarString = LdapVarString;
// "ldap://" + host
class LdapStringVar extends BinaryExpr {
LdapStringVar() {
@@ -103,9 +85,6 @@ class LdapStringVar extends BinaryExpr {
}
}
/** DEPRECATED: Alias for LdapStringVar */
deprecated class LDAPStringVar = LdapStringVar;
/**
* A taint-tracking configuration for detecting LDAP insecure authentications.
*/
@@ -125,6 +104,3 @@ class LdapInsecureAuthConfig extends TaintTracking::Configuration {
exists(LdapBind ldapBind | not ldapBind.useSsl() and sink = ldapBind.getHost())
}
}
/** DEPRECATED: Alias for LdapInsecureAuthConfig */
deprecated class LDAPInsecureAuthConfig = LdapInsecureAuthConfig;

View File

@@ -52,6 +52,3 @@ module NoSqlInjection {
ConvertedToDict() { this = "ConvertedToDict" }
}
}
/** DEPRECATED: Alias for NoSqlInjection */
deprecated module NoSQLInjection = NoSqlInjection;

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