Merge branch 'main' into jcogs33/shared-sink-kind-validation

This commit is contained in:
Jami
2023-06-14 08:06:34 -04:00
committed by GitHub
893 changed files with 16779 additions and 17965 deletions

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

@@ -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

@@ -38,6 +38,7 @@ private import DataFlowPrivate
private import FlowSummaryImpl as FlowSummaryImpl
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import semmle.python.internal.CachedStages
private import semmle.python.dataflow.new.internal.TypeTracker::CallGraphConstruction as CallGraphConstruction
newtype TParameterPosition =
/** Used for `self` in methods, and `cls` in classmethods. */
@@ -464,103 +465,105 @@ private predicate ignoreForCallGraph(File f) {
f.getAbsolutePath().matches("%/site-packages/sympy/%")
}
/**
* Gets a reference to the function `func`.
*/
private TypeTrackingNode functionTracker(TypeTracker t, Function func) {
not ignoreForCallGraph(result.getLocation().getFile()) and
t.start() and
(
result.asExpr() = func.getDefinition()
private module TrackFunctionInput implements CallGraphConstruction::Simple::InputSig {
class State = Function;
predicate start(Node start, Function func) {
start.asExpr() = func.getDefinition()
or
// when a function is decorated, it's the result of the (last) decorator call that
// is used
result.asExpr() = func.getDefinition().(FunctionExpr).getADecoratorCall()
)
or
not ignoreForCallGraph(result.getLocation().getFile()) and
exists(TypeTracker t2 | result = functionTracker(t2, func).track(t2, t))
start.asExpr() = func.getDefinition().(FunctionExpr).getADecoratorCall()
}
predicate filter(Node n) { ignoreForCallGraph(n.getLocation().getFile()) }
}
/**
* Gets a reference to the function `func`.
*/
Node functionTracker(Function func) { functionTracker(TypeTracker::end(), func).flowsTo(result) }
Node functionTracker(Function func) {
CallGraphConstruction::Simple::Make<TrackFunctionInput>::track(func)
.(LocalSourceNode)
.flowsTo(result)
}
/**
* Gets a reference to the class `cls`.
*/
private TypeTrackingNode classTracker(TypeTracker t, Class cls) {
not ignoreForCallGraph(result.getLocation().getFile()) and
t.start() and
(
result.asExpr() = cls.getParent()
private module TrackClassInput implements CallGraphConstruction::Simple::InputSig {
class State = Class;
predicate start(Node start, Class cls) {
start.asExpr() = cls.getParent()
or
// when a class is decorated, it's the result of the (last) decorator call that
// is used
result.asExpr() = cls.getParent().getADecoratorCall()
start.asExpr() = cls.getParent().getADecoratorCall()
or
// `type(obj)`, where obj is an instance of this class
result = getTypeCall() and
result.(CallCfgNode).getArg(0) = classInstanceTracker(cls)
)
or
not ignoreForCallGraph(result.getLocation().getFile()) and
exists(TypeTracker t2 | result = classTracker(t2, cls).track(t2, t)) and
not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
start = getTypeCall() and
start.(CallCfgNode).getArg(0) = classInstanceTracker(cls)
}
predicate filter(Node n) {
ignoreForCallGraph(n.getLocation().getFile())
or
n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
}
}
/**
* Gets a reference to the class `cls`.
*/
Node classTracker(Class cls) { classTracker(TypeTracker::end(), cls).flowsTo(result) }
Node classTracker(Class cls) {
CallGraphConstruction::Simple::Make<TrackClassInput>::track(cls).(LocalSourceNode).flowsTo(result)
}
/**
* Gets a reference to an instance of the class `cls`.
*/
private TypeTrackingNode classInstanceTracker(TypeTracker t, Class cls) {
not ignoreForCallGraph(result.getLocation().getFile()) and
t.start() and
resolveClassCall(result.(CallCfgNode).asCfgNode(), cls)
or
// result of `super().__new__` as used in a `__new__` method implementation
not ignoreForCallGraph(result.getLocation().getFile()) and
t.start() and
exists(Class classUsedInSuper |
fromSuperNewCall(result.(CallCfgNode).asCfgNode(), classUsedInSuper, _, _) and
classUsedInSuper = getADirectSuperclass*(cls)
)
or
not ignoreForCallGraph(result.getLocation().getFile()) and
exists(TypeTracker t2 | result = classInstanceTracker(t2, cls).track(t2, t)) and
not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
private module TrackClassInstanceInput implements CallGraphConstruction::Simple::InputSig {
class State = Class;
predicate start(Node start, Class cls) {
resolveClassCall(start.(CallCfgNode).asCfgNode(), cls)
or
// result of `super().__new__` as used in a `__new__` method implementation
exists(Class classUsedInSuper |
fromSuperNewCall(start.(CallCfgNode).asCfgNode(), classUsedInSuper, _, _) and
classUsedInSuper = getADirectSuperclass*(cls)
)
}
predicate filter(Node n) {
ignoreForCallGraph(n.getLocation().getFile())
or
n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
}
}
/**
* Gets a reference to an instance of the class `cls`.
*/
Node classInstanceTracker(Class cls) {
classInstanceTracker(TypeTracker::end(), cls).flowsTo(result)
CallGraphConstruction::Simple::Make<TrackClassInstanceInput>::track(cls)
.(LocalSourceNode)
.flowsTo(result)
}
/**
* Gets a reference to the `self` argument of a method on class `classWithMethod`.
* The method cannot be a `staticmethod` or `classmethod`.
*/
private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) {
not ignoreForCallGraph(result.getLocation().getFile()) and
t.start() and
exists(Function func |
func = classWithMethod.getAMethod() and
not isStaticmethod(func) and
not isClassmethod(func)
|
result.asExpr() = func.getArg(0)
)
or
not ignoreForCallGraph(result.getLocation().getFile()) and
exists(TypeTracker t2 | result = selfTracker(t2, classWithMethod).track(t2, t)) and
not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
private module TrackSelfInput implements CallGraphConstruction::Simple::InputSig {
class State = Class;
predicate start(Node start, Class classWithMethod) {
exists(Function func |
func = classWithMethod.getAMethod() and
not isStaticmethod(func) and
not isClassmethod(func)
|
start.asExpr() = func.getArg(0)
)
}
predicate filter(Node n) {
ignoreForCallGraph(n.getLocation().getFile())
or
n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
}
}
/**
@@ -568,33 +571,32 @@ private TypeTrackingNode selfTracker(TypeTracker t, Class classWithMethod) {
* The method cannot be a `staticmethod` or `classmethod`.
*/
Node selfTracker(Class classWithMethod) {
selfTracker(TypeTracker::end(), classWithMethod).flowsTo(result)
CallGraphConstruction::Simple::Make<TrackSelfInput>::track(classWithMethod)
.(LocalSourceNode)
.flowsTo(result)
}
/**
* Gets a reference to the enclosing class `classWithMethod` from within one of its
* methods, either through the `cls` argument from a `classmethod` or from `type(self)`
* from a normal method.
*/
private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod) {
not ignoreForCallGraph(result.getLocation().getFile()) and
t.start() and
(
private module TrackClsArgumentInput implements CallGraphConstruction::Simple::InputSig {
class State = Class;
predicate start(Node start, Class classWithMethod) {
exists(Function func |
func = classWithMethod.getAMethod() and
isClassmethod(func)
|
result.asExpr() = func.getArg(0)
start.asExpr() = func.getArg(0)
)
or
// type(self)
result = getTypeCall() and
result.(CallCfgNode).getArg(0) = selfTracker(classWithMethod)
)
or
not ignoreForCallGraph(result.getLocation().getFile()) and
exists(TypeTracker t2 | result = clsArgumentTracker(t2, classWithMethod).track(t2, t)) and
not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
start = getTypeCall() and
start.(CallCfgNode).getArg(0) = selfTracker(classWithMethod)
}
predicate filter(Node n) {
ignoreForCallGraph(n.getLocation().getFile())
or
n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
}
}
/**
@@ -603,26 +605,28 @@ private TypeTrackingNode clsArgumentTracker(TypeTracker t, Class classWithMethod
* from a normal method.
*/
Node clsArgumentTracker(Class classWithMethod) {
clsArgumentTracker(TypeTracker::end(), classWithMethod).flowsTo(result)
CallGraphConstruction::Simple::Make<TrackClsArgumentInput>::track(classWithMethod)
.(LocalSourceNode)
.flowsTo(result)
}
/**
* Gets a reference to the result of calling `super` without any argument, where the
* call happened in the method `func` (either a method or a classmethod).
*/
private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func) {
not ignoreForCallGraph(result.getLocation().getFile()) and
t.start() and
not isStaticmethod(func) and
exists(CallCfgNode call | result = call |
call = getSuperCall() and
not exists(call.getArg(_)) and
call.getScope() = func
)
or
not ignoreForCallGraph(result.getLocation().getFile()) and
exists(TypeTracker t2 | result = superCallNoArgumentTracker(t2, func).track(t2, t)) and
not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
private module TrackSuperCallNoArgumentInput implements CallGraphConstruction::Simple::InputSig {
class State = Function;
predicate start(Node start, Function func) {
not isStaticmethod(func) and
exists(CallCfgNode call | start = call |
call = getSuperCall() and
not exists(call.getArg(_)) and
call.getScope() = func
)
}
predicate filter(Node n) {
ignoreForCallGraph(n.getLocation().getFile())
or
n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
}
}
/**
@@ -630,25 +634,30 @@ private TypeTrackingNode superCallNoArgumentTracker(TypeTracker t, Function func
* call happened in the method `func` (either a method or a classmethod).
*/
Node superCallNoArgumentTracker(Function func) {
superCallNoArgumentTracker(TypeTracker::end(), func).flowsTo(result)
CallGraphConstruction::Simple::Make<TrackSuperCallNoArgumentInput>::track(func)
.(LocalSourceNode)
.flowsTo(result)
}
/**
* Gets a reference to the result of calling `super` with 2 arguments, where the
* first is a reference to the class `cls`, and the second argument is `obj`.
*/
private TypeTrackingNode superCallTwoArgumentTracker(TypeTracker t, Class cls, Node obj) {
not ignoreForCallGraph(result.getLocation().getFile()) and
t.start() and
exists(CallCfgNode call | result = call |
private module TrackSuperCallTwoArgumentInput implements CallGraphConstruction::Simple::InputSig {
additional predicate superCall(CallCfgNode call, Class cls, Node obj) {
call = getSuperCall() and
call.getArg(0) = classTracker(cls) and
call.getArg(1) = obj
)
or
not ignoreForCallGraph(result.getLocation().getFile()) and
exists(TypeTracker t2 | result = superCallTwoArgumentTracker(t2, cls, obj).track(t2, t)) and
not result.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
}
class State = CallCfgNode;
predicate start(Node start, CallCfgNode call) {
superCall(call, _, _) and
start = call
}
predicate filter(Node n) {
ignoreForCallGraph(n.getLocation().getFile())
or
n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
}
}
/**
@@ -656,7 +665,12 @@ private TypeTrackingNode superCallTwoArgumentTracker(TypeTracker t, Class cls, N
* first is a reference to the class `cls`, and the second argument is `obj`.
*/
Node superCallTwoArgumentTracker(Class cls, Node obj) {
superCallTwoArgumentTracker(TypeTracker::end(), cls, obj).flowsTo(result)
exists(CallCfgNode call |
TrackSuperCallTwoArgumentInput::superCall(call, cls, obj) and
CallGraphConstruction::Simple::Make<TrackSuperCallTwoArgumentInput>::track(call)
.(LocalSourceNode)
.flowsTo(result)
)
}
// =============================================================================
@@ -800,20 +814,30 @@ Function findFunctionAccordingToMroKnownStartingClass(Class startingClass, strin
// =============================================================================
// attribute trackers
// =============================================================================
/** Gets a reference to the attribute read `attr` */
private TypeTrackingNode attrReadTracker(TypeTracker t, AttrRead attr) {
t.start() and
result = attr and
attr.getObject() in [
classTracker(_), classInstanceTracker(_), selfTracker(_), clsArgumentTracker(_),
superCallNoArgumentTracker(_), superCallTwoArgumentTracker(_, _)
]
or
exists(TypeTracker t2 | result = attrReadTracker(t2, attr).track(t2, t))
private module TrackAttrReadInput implements CallGraphConstruction::Simple::InputSig {
class State = AttrRead;
predicate start(Node start, AttrRead attr) {
start = attr and
attr.getObject() in [
classTracker(_), classInstanceTracker(_), selfTracker(_), clsArgumentTracker(_),
superCallNoArgumentTracker(_), superCallTwoArgumentTracker(_, _)
]
}
predicate filter(Node n) {
ignoreForCallGraph(n.getLocation().getFile())
or
n.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pp | pp.isSelf()))
}
}
/** Gets a reference to the attribute read `attr` */
Node attrReadTracker(AttrRead attr) { attrReadTracker(TypeTracker::end(), attr).flowsTo(result) }
Node attrReadTracker(AttrRead attr) {
CallGraphConstruction::Simple::Make<TrackAttrReadInput>::track(attr)
.(LocalSourceNode)
.flowsTo(result)
}
// =============================================================================
// call and argument resolution
@@ -1292,7 +1316,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)
}
@@ -1424,12 +1450,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 }
@@ -1462,44 +1488,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(
@@ -1513,26 +1530,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 }
}
@@ -1601,11 +1622,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

@@ -1135,8 +1135,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,17 +1199,21 @@ 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]
@@ -1339,6 +1343,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 +1368,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 +1529,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 +1789,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 +1972,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
(
@@ -2197,8 +2206,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 +2227,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 +2256,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 +2299,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 +2358,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 +2390,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 +2604,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 +2634,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 +2657,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 +2674,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, _)
)
}
@@ -2820,9 +2845,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 |
@@ -3340,13 +3363,24 @@ 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
) {
@@ -3964,7 +3998,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 +4024,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 +4045,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 +4231,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 +4358,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

@@ -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. */
@@ -502,6 +504,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 +531,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 +605,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 +798,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 +835,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 +877,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 +934,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 +961,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

@@ -180,6 +180,11 @@ module Public {
result = "Argument[" + getParameterPosition(pos) + "]"
)
or
exists(string synthetic |
sc = TSyntheticGlobalSummaryComponent(synthetic) and
result = "SyntheticGlobal[" + synthetic + "]"
)
or
sc = TReturnSummaryComponent(getReturnValueKind()) and result = "ReturnValue"
}
@@ -505,6 +510,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 +538,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 +567,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 +618,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 +626,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 +649,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 +664,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 +672,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 +680,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 +693,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 +708,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 +721,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 +742,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 +754,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 +769,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 +778,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 +792,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 +804,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 +821,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 +847,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 +859,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 +871,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 +898,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 +910,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 +920,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 +942,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 +967,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 +1006,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 +1021,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 +1034,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 +1048,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)
)
}
@@ -1344,11 +1416,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 +1429,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 +1449,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() }

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)
}
}
@@ -190,14 +192,9 @@ predicate containerStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
call.getArg(0) = nodeFrom
)
or
// methods
// dict methods
exists(DataFlow::MethodCallNode call, string methodName | call = nodeTo |
methodName in [
// general
"copy", "pop",
// dict
"values", "items", "get", "popitem"
] and
methodName in ["values", "items"] and
call.calls(nodeFrom, methodName)
)
or

View File

@@ -224,6 +224,50 @@ private module Cached {
private import Cached
private predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
stepNoCall(nodeFrom, nodeTo, summary)
or
stepCall(nodeFrom, nodeTo, summary)
}
pragma[nomagic]
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
smallstepCall(nodeFrom, nodeTo, summary)
}
pragma[nomagic]
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`.
*
@@ -298,21 +342,50 @@ class StepSummary extends TStepSummary {
module StepSummary {
/**
* Gets the summary that corresponds to having taken a forwards
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
* inter-procedural step from `nodeFrom` to `nodeTo`.
*
* This predicate is inlined, which enables better join-orders when
* the call graph construction and type tracking are mutually recursive.
* In such cases, non-linear recursion involving `step` will be limited
* to non-linear recursion for the parts of `step` that involve the
* call graph.
* This predicate should normally not be used; consider using `step`
* instead.
*/
predicate stepCall = Cached::stepCall/3;
/**
* Gets the summary that corresponds to having taken a forwards
* intra-procedural step from `nodeFrom` to `nodeTo`.
*
* This predicate should normally not be used; consider using `step`
* instead.
*/
predicate stepNoCall = Cached::stepNoCall/3;
/**
* Gets the summary that corresponds to having taken a forwards
* heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
*/
pragma[inline]
predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
stepNoCall(nodeFrom, nodeTo, summary)
or
stepCall(nodeFrom, nodeTo, summary)
}
/**
* Gets the summary that corresponds to having taken a forwards
* inter-procedural step from `nodeFrom` to `nodeTo`.
*
* This predicate should normally not be used; consider using `step`
* instead.
*/
predicate smallstepNoCall = Cached::smallstepNoCall/3;
/**
* Gets the summary that corresponds to having taken a forwards
* intra-procedural step from `nodeFrom` to `nodeTo`.
*
* This predicate should normally not be used; consider using `step`
* instead.
*/
predicate smallstepCall = Cached::smallstepCall/3;
/**
* Gets the summary that corresponds to having taken a forwards
* local, heap and/or inter-procedural step from `nodeFrom` to `nodeTo`.
@@ -320,7 +393,6 @@ module StepSummary {
* Unlike `StepSummary::step`, this predicate does not compress
* type-preserving steps.
*/
pragma[inline]
predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
smallstepNoCall(nodeFrom, nodeTo, summary)
or
@@ -431,10 +503,7 @@ class TypeTracker extends TTypeTracker {
*/
pragma[inline]
TypeTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
exists(StepSummary summary |
StepSummary::step(nodeFrom, pragma[only_bind_out](nodeTo), pragma[only_bind_into](summary)) and
result = this.append(pragma[only_bind_into](summary))
)
result = stepInlineLate(this, nodeFrom, nodeTo)
}
/**
@@ -463,10 +532,7 @@ class TypeTracker extends TTypeTracker {
*/
pragma[inline]
TypeTracker smallstep(Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
StepSummary::smallstep(nodeFrom, nodeTo, summary) and
result = this.append(summary)
)
result = smallstepInlineLate(this, nodeFrom, nodeTo)
or
simpleLocalFlowStep(nodeFrom, nodeTo) and
result = this
@@ -481,6 +547,39 @@ module TypeTracker {
TypeTracker end() { result.end() }
}
pragma[nomagic]
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.
*
@@ -564,10 +663,7 @@ class TypeBackTracker extends TTypeBackTracker {
*/
pragma[inline]
TypeBackTracker step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo) {
exists(StepSummary summary |
StepSummary::step(pragma[only_bind_out](nodeFrom), nodeTo, pragma[only_bind_into](summary)) and
this = result.prepend(pragma[only_bind_into](summary))
)
this = backStepInlineLate(result, nodeFrom, nodeTo)
}
/**
@@ -596,10 +692,7 @@ class TypeBackTracker extends TTypeBackTracker {
*/
pragma[inline]
TypeBackTracker smallstep(Node nodeFrom, Node nodeTo) {
exists(StepSummary summary |
StepSummary::smallstep(nodeFrom, nodeTo, summary) and
this = result.prepend(summary)
)
this = backSmallstepInlineLate(result, nodeFrom, nodeTo)
or
simpleLocalFlowStep(nodeFrom, nodeTo) and
this = result
@@ -635,3 +728,169 @@ module TypeBackTracker {
*/
TypeBackTracker end() { result.end() }
}
/**
* INTERNAL: Do not use.
*
* Provides logic for constructing a call graph in mutual recursion with type tracking.
*
* When type tracking is used to construct a call graph, we cannot use the join-order
* from `stepInlineLate`, because `step` becomes a recursive call, which means that we
* will have a conjunct with 3 recursive calls: the call to `step`, the call to `stepProj`,
* and the recursive type tracking call itself. The solution is to split the three-way
* non-linear recursion into two non-linear predicates: one that first joins with the
* projected `stepCall` relation, followed by a predicate that joins with the full
* `stepCall` relation (`stepNoCall` not being recursive, can be join-ordered in the
* same way as in `stepInlineLate`).
*/
module CallGraphConstruction {
/** The input to call graph construction. */
signature module InputSig {
/** A state to track during type tracking. */
class State;
/** Holds if type tracking should start at `start` in state `state`. */
predicate start(Node start, State state);
/**
* Holds if type tracking should use the step from `nodeFrom` to `nodeTo`,
* which _does not_ depend on the call graph.
*
* Implementing this predicate using `StepSummary::[small]stepNoCall` yields
* standard type tracking.
*/
predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary);
/**
* Holds if type tracking should use the step from `nodeFrom` to `nodeTo`,
* which _does_ depend on the call graph.
*
* Implementing this predicate using `StepSummary::[small]stepCall` yields
* standard type tracking.
*/
predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary);
/** A projection of an element from the state space. */
class StateProj;
/** Gets the projection of `state`. */
StateProj stateProj(State state);
/** Holds if type tracking should stop at `n` when we are tracking projected state `stateProj`. */
predicate filter(Node n, StateProj stateProj);
}
/** Provides the `track` predicate for use in call graph construction. */
module Make<InputSig Input> {
pragma[nomagic]
private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) {
Input::stepNoCall(nodeFrom, _, summary)
}
pragma[nomagic]
private predicate stepCallProj(Node nodeFrom, StepSummary summary) {
Input::stepCall(nodeFrom, _, summary)
}
bindingset[nodeFrom, t]
pragma[inline_late]
pragma[noopt]
private TypeTracker stepNoCallInlineLate(
TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo
) {
exists(StepSummary summary |
stepNoCallProj(nodeFrom, summary) and
result = t.append(summary) and
Input::stepNoCall(nodeFrom, nodeTo, summary)
)
}
bindingset[state]
pragma[inline_late]
private Input::StateProj stateProjInlineLate(Input::State state) {
result = Input::stateProj(state)
}
pragma[nomagic]
private Node track(Input::State state, TypeTracker t) {
t.start() and Input::start(result, state)
or
exists(Input::StateProj stateProj |
stateProj = stateProjInlineLate(state) and
not Input::filter(result, stateProj)
|
exists(TypeTracker t2 | t = stepNoCallInlineLate(t2, track(state, t2), result))
or
exists(StepSummary summary |
// non-linear recursion
Input::stepCall(trackCall(state, t, summary), result, summary)
)
)
}
bindingset[t, summary]
pragma[inline_late]
private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) {
result = t.append(summary)
}
pragma[nomagic]
private Node trackCall(Input::State state, TypeTracker t, StepSummary summary) {
exists(TypeTracker t2 |
// non-linear recursion
result = track(state, t2) and
stepCallProj(result, summary) and
t = appendInlineLate(t2, summary)
)
}
/** Gets a node that can be reached from _some_ start node in state `state`. */
pragma[nomagic]
Node track(Input::State state) { result = track(state, TypeTracker::end()) }
}
/** A simple version of `CallGraphConstruction` that uses standard type tracking. */
module Simple {
/** The input to call graph construction. */
signature module InputSig {
/** A state to track during type tracking. */
class State;
/** Holds if type tracking should start at `start` in state `state`. */
predicate start(Node start, State state);
/** Holds if type tracking should stop at `n`. */
predicate filter(Node n);
}
/** Provides the `track` predicate for use in call graph construction. */
module Make<InputSig Input> {
private module I implements CallGraphConstruction::InputSig {
private import codeql.util.Unit
class State = Input::State;
predicate start(Node start, State state) { Input::start(start, state) }
predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary) {
StepSummary::stepNoCall(nodeFrom, nodeTo, summary)
}
predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary) {
StepSummary::stepCall(nodeFrom, nodeTo, summary)
}
class StateProj = Unit;
Unit stateProj(State state) { exists(state) and exists(result) }
predicate filter(Node n, Unit u) {
Input::filter(n) and
exists(u)
}
}
import CallGraphConstruction::Make<I>
}
}
}

View File

@@ -664,14 +664,6 @@ module DataFlow {
}
}
deprecated private class DataFlowType extends TaintKind {
// this only exists to avoid an empty recursion error in the type checker
DataFlowType() {
this = "Data flow" and
1 = 2
}
}
pragma[noinline]
private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) {
dictnode.(DictNode).getAValue() = itemnode

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
// ---------------------------------------------------------------------------
@@ -3939,6 +3900,176 @@ private module StdlibPrivate {
}
}
// ---------------------------------------------------------------------------
// 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]"
)
}
}
/**
* A flow summary for `dict.setdefault`.
*
@@ -3962,6 +4093,40 @@ 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
}
}
}
// ---------------------------------------------------------------------------

View File

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

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,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,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,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

@@ -34,4 +34,4 @@ where
)
)
select div, "Result of division may be truncated as its $@ and $@ arguments may both be integers.",
left.getLocation(), "left", right.getLocation(), "right"
left, "left", right, "right"

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

@@ -1,5 +1,5 @@
/**
* @name Deserializing untrusted input
* @name Deserialization of user-controlled data
* @description Deserializing user-controlled data may allow attackers to execute arbitrary code.
* @kind path-problem
* @id py/unsafe-deserialization

View File

@@ -36,5 +36,5 @@ where
ex = Value::named("sys.exc_info") and
ex.getACall().getScope() = f
)
select del, "Unnecessary deletion of local variable $@ in function $@.", e.getLocation(),
e.toString(), f.getLocation(), f.getName()
select del, "Unnecessary deletion of local variable $@ in function $@.", e, e.toString(), f,
f.getName()

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* The display name (`@name`) of the `py/unsafe-deserialization` query has been updated in favor of consistency with other languages.

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;

View File

@@ -1,2 +1,2 @@
| TruncatedDivision_test.py:65:7:65:11 | BinaryExpr | Result of division may be truncated as its $@ and $@ arguments may both be integers. | TruncatedDivision_test.py:65:7:65:7 | TruncatedDivision_test.py:65 | left | TruncatedDivision_test.py:65:11:65:11 | TruncatedDivision_test.py:65 | right |
| TruncatedDivision_test.py:72:7:72:35 | BinaryExpr | Result of division may be truncated as its $@ and $@ arguments may both be integers. | TruncatedDivision_test.py:25:12:25:12 | TruncatedDivision_test.py:25 | left | TruncatedDivision_test.py:28:12:28:12 | TruncatedDivision_test.py:28 | right |
| TruncatedDivision_test.py:65:7:65:11 | BinaryExpr | Result of division may be truncated as its $@ and $@ arguments may both be integers. | TruncatedDivision_test.py:65:7:65:7 | ControlFlowNode for IntegerLiteral | left | TruncatedDivision_test.py:65:11:65:11 | ControlFlowNode for IntegerLiteral | right |
| TruncatedDivision_test.py:72:7:72:35 | BinaryExpr | Result of division may be truncated as its $@ and $@ arguments may both be integers. | TruncatedDivision_test.py:25:12:25:12 | ControlFlowNode for IntegerLiteral | left | TruncatedDivision_test.py:28:12:28:12 | ControlFlowNode for IntegerLiteral | right |

View File

@@ -1 +1 @@
| nonsense.py:0:1:0:1 | Syntax Error | Syntax Error (in Python 2). |
| nonsense.py:1:1:1:1 | Syntax Error | Syntax Error (in Python 2). |

View File

@@ -1 +1 @@
| nonsense.py:0:1:0:1 | Syntax Error | Syntax Error (in Python 3). |
| nonsense.py:1:2:1:2 | Syntax Error | Syntax Error (in Python 3). |

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -4,16 +4,14 @@ import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch
import TestUtilities.InlineExpectationsTest
private import semmle.python.dataflow.new.internal.PrintNode
class DataFlowCallTest extends InlineExpectationsTest {
DataFlowCallTest() { this = "DataFlowCallTest" }
override string getARelevantTag() {
module DataFlowCallTest implements TestSig {
string getARelevantTag() {
result in ["call", "callType"]
or
result = "arg[" + any(DataFlowDispatch::ArgumentPosition pos).toString() + "]"
}
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(DataFlowDispatch::DataFlowCall call |
location = call.getLocation() and
@@ -35,3 +33,5 @@ class DataFlowCallTest extends InlineExpectationsTest {
)
}
}
import MakeTest<DataFlowCallTest>

View File

@@ -57,7 +57,7 @@ def test_list_from_set():
s = {SOURCE}
l = list(s)
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
@expects(2)
def test_list_from_dict():
d = {SOURCE: 'v', NONSOURCE: 'v2'}
@@ -154,19 +154,19 @@ def test_list_pop():
def test_list_pop_index():
l = [SOURCE]
v = l.pop(0)
SINK(v) #$ MISSING: flow="SOURCE, l:-2 -> v"
SINK(v) #$ flow="SOURCE, l:-2 -> v"
def test_list_pop_index_imprecise():
l = [SOURCE, NONSOURCE]
v = l.pop(1)
SINK_F(v)
SINK_F(v) #$ SPURIOUS: flow="SOURCE, l:-2 -> v"
@expects(2)
def test_list_copy():
l0 = [SOURCE, NONSOURCE]
l = l0.copy()
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1])
SINK(l[0]) #$ flow="SOURCE, l:-2 -> l[0]"
SINK_F(l[1]) #$ SPURIOUS: flow="SOURCE, l:-3 -> l[1]"
def test_list_append():
l = [NONSOURCE]
@@ -183,7 +183,7 @@ def test_set_pop():
def test_set_copy():
s0 = {SOURCE}
s = s0.copy()
SINK(s.pop()) #$ MISSING: flow="SOURCE, l:-2 -> s.pop()"
SINK(s.pop()) #$ flow="SOURCE, l:-2 -> s.pop()"
def test_set_add():
s = set([])
@@ -222,28 +222,31 @@ def test_dict_pop():
v1 = d.pop("k", NONSOURCE)
SINK_F(v1) #$ SPURIOUS: flow="SOURCE, l:-4 -> v1"
v2 = d.pop("non-existing", SOURCE)
SINK(v2) #$ MISSING: flow="SOURCE, l:-1 -> v2"
SINK(v2) #$ flow="SOURCE, l:-1 -> v2"
@expects(2)
@expects(3)
def test_dict_get():
d = {'k': SOURCE}
v = d.get("k")
SINK(v) #$ flow="SOURCE, l:-2 -> v"
v1 = d.get("non-existing", SOURCE)
SINK(v1) #$ MISSING: flow="SOURCE, l:-1 -> v1"
SINK(v1) #$ flow="SOURCE, l:-1 -> v1"
k = "k"
v2 = d.get(k)
SINK(v2) #$ flow="SOURCE, l:-7 -> v2"
@expects(2)
def test_dict_popitem():
d = {'k': SOURCE}
t = d.popitem() # could be any pair (before 3.7), but we only have one
SINK_F(t[0])
SINK(t[1]) #$ MISSING: flow="SOURCE, l:-3 -> t[1]"
SINK(t[1]) #$ flow="SOURCE, l:-3 -> t[1]"
@expects(2)
def test_dict_copy():
d = {'k': SOURCE, 'k1': NONSOURCE}
d1 = d.copy()
SINK(d1["k"]) #$ MISSING: flow="SOURCE, l:-2 -> d[k]"
SINK(d1["k"]) #$ flow="SOURCE, l:-2 -> d1['k']"
SINK_F(d1["k1"])
@@ -354,4 +357,4 @@ def test_next_dict():
d = {SOURCE: "val"}
i = iter(d)
n = next(i)
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -2,12 +2,10 @@ import python
import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
class GlobalReadTest extends InlineExpectationsTest {
GlobalReadTest() { this = "GlobalReadTest" }
module GlobalReadTest implements TestSig {
string getARelevantTag() { result = "reads" }
override string getARelevantTag() { result = "reads" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::ModuleVariableNode n, DataFlow::Node read |
read = n.getARead() and
value = n.getVariable().getId() and
@@ -19,12 +17,10 @@ class GlobalReadTest extends InlineExpectationsTest {
}
}
class GlobalWriteTest extends InlineExpectationsTest {
GlobalWriteTest() { this = "GlobalWriteTest" }
module GlobalWriteTest implements TestSig {
string getARelevantTag() { result = "writes" }
override string getARelevantTag() { result = "writes" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::ModuleVariableNode n, DataFlow::Node read |
read = n.getAWrite() and
value = n.getVariable().getId() and
@@ -34,3 +30,5 @@ class GlobalWriteTest extends InlineExpectationsTest {
)
}
}
import MakeTest<MergeTests<GlobalReadTest, GlobalWriteTest>>

View File

@@ -8,12 +8,10 @@ import TestUtilities.InlineExpectationsTest
import semmle.python.dataflow.new.SensitiveDataSources
private import semmle.python.ApiGraphs
class SensitiveDataSourcesTest extends InlineExpectationsTest {
SensitiveDataSourcesTest() { this = "SensitiveDataSourcesTest" }
module SensitiveDataSourcesTest implements TestSig {
string getARelevantTag() { result in ["SensitiveDataSource", "SensitiveUse"] }
override string getARelevantTag() { result in ["SensitiveDataSource", "SensitiveUse"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(SensitiveDataSource source |
location = source.getLocation() and
@@ -32,6 +30,8 @@ class SensitiveDataSourcesTest extends InlineExpectationsTest {
}
}
import MakeTest<SensitiveDataSourcesTest>
class SensitiveUseConfiguration extends TaintTracking::Configuration {
SensitiveUseConfiguration() { this = "SensitiveUseConfiguration" }

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -3,12 +3,10 @@ import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
import experimental.dataflow.testConfig
class CaptureTest extends InlineExpectationsTest {
CaptureTest() { this = "CaptureTest" }
module CaptureTest implements TestSig {
string getARelevantTag() { result = "captured" }
override string getARelevantTag() { result = "captured" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node sink | exists(TestConfiguration cfg | cfg.hasFlowTo(sink)) |
location = sink.getLocation() and
tag = "captured" and
@@ -17,3 +15,5 @@ class CaptureTest extends InlineExpectationsTest {
)
}
}
import MakeTest<CaptureTest>

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -72,12 +72,10 @@ private class ImportConfiguration extends DataFlow::Configuration {
}
}
class ResolutionTest extends InlineExpectationsTest {
ResolutionTest() { this = "ResolutionTest" }
module ResolutionTest implements TestSig {
string getARelevantTag() { result = "prints" }
override string getARelevantTag() { result = "prints" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
(
exists(DataFlow::PathNode source, DataFlow::PathNode sink, ImportConfiguration config |
config.hasFlowPath(source, sink) and
@@ -105,12 +103,10 @@ private string getTagForVersion(int version) {
version = major_version()
}
class VersionSpecificResolutionTest extends InlineExpectationsTest {
VersionSpecificResolutionTest() { this = "VersionSpecificResolutionTest" }
module VersionSpecificResolutionTest implements TestSig {
string getARelevantTag() { result = getTagForVersion(_) }
override string getARelevantTag() { result = getTagForVersion(_) }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
(
exists(DataFlow::PathNode source, DataFlow::PathNode sink, ImportConfiguration config |
config.hasFlowPath(source, sink) and
@@ -130,3 +126,5 @@ class VersionSpecificResolutionTest extends InlineExpectationsTest {
)
}
}
import MakeTest<MergeTests<ResolutionTest, VersionSpecificResolutionTest>>

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -18,12 +18,10 @@ private class ImmediateModuleRef extends DataFlow::Node {
string getAsname() { result = alias }
}
class ImportTest extends InlineExpectationsTest {
ImportTest() { this = "ImportTest" }
module ImportTest implements TestSig {
string getARelevantTag() { result = "imports" }
override string getARelevantTag() { result = "imports" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(ImmediateModuleRef ref |
tag = "imports" and
location = ref.getLocation() and
@@ -33,12 +31,10 @@ class ImportTest extends InlineExpectationsTest {
}
}
class AliasTest extends InlineExpectationsTest {
AliasTest() { this = "AliasTest" }
module AliasTest implements TestSig {
string getARelevantTag() { result = "as" }
override string getARelevantTag() { result = "as" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(ImmediateModuleRef ref |
tag = "as" and
location = ref.getLocation() and
@@ -47,3 +43,5 @@ class AliasTest extends InlineExpectationsTest {
)
}
}
import MakeTest<MergeTests<ImportTest, AliasTest>>

View File

@@ -1,4 +1,5 @@
failures
testFailures
debug_callableNotUnique
pointsTo_found_typeTracker_notFound
typeTracker_found_pointsTo_notFound

View File

@@ -1,4 +1,5 @@
failures
testFailures
debug_callableNotUnique
pointsTo_found_typeTracker_notFound
typeTracker_found_pointsTo_notFound

View File

@@ -1,4 +1,5 @@
failures
testFailures
debug_callableNotUnique
pointsTo_found_typeTracker_notFound
| code/class_attr_assign.py:10:9:10:27 | ControlFlowNode for Attribute() | my_func |

View File

@@ -37,12 +37,10 @@ predicate typeTrackerClassCall(CallNode call, Function callable) {
)
}
class CallGraphTest extends InlineExpectationsTest {
CallGraphTest() { this = "CallGraphTest" }
module CallGraphTest implements TestSig {
string getARelevantTag() { result in ["pt", "tt"] }
override string getARelevantTag() { result in ["pt", "tt"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(CallNode call, Function target |
tag = "tt" and
@@ -58,6 +56,8 @@ class CallGraphTest extends InlineExpectationsTest {
}
}
import MakeTest<CallGraphTest>
bindingset[call, target]
string getCallEdgeValue(CallNode call, Function target) {
if call.getLocation().getFile() = target.getLocation().getFile()

View File

@@ -3,6 +3,7 @@ edges
| UnsafeUnpack.py:5:26:5:32 | GSSA Variable request | UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request |
| UnsafeUnpack.py:11:18:11:24 | ControlFlowNode for request | UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute |
| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() |
| UnsafeUnpack.py:11:18:11:29 | ControlFlowNode for Attribute | UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute |
| UnsafeUnpack.py:11:18:11:49 | ControlFlowNode for Attribute() | UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute |
| UnsafeUnpack.py:17:27:17:38 | ControlFlowNode for Attribute | UnsafeUnpack.py:19:35:19:41 | ControlFlowNode for tarpath |
| UnsafeUnpack.py:33:50:33:65 | ControlFlowNode for local_ziped_path | UnsafeUnpack.py:34:23:34:38 | ControlFlowNode for local_ziped_path |
@@ -15,7 +16,9 @@ edges
| UnsafeUnpack.py:103:23:103:27 | SSA variable chunk | UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath |
| UnsafeUnpack.py:103:32:103:44 | ControlFlowNode for Attribute | UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript |
| UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | UnsafeUnpack.py:103:23:103:27 | SSA variable chunk |
| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:108:22:108:48 | ControlFlowNode for Attribute() |
| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path |
| UnsafeUnpack.py:108:22:108:48 | ControlFlowNode for Attribute() | UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path |
| UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute |
| UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | UnsafeUnpack.py:116:17:116:21 | SSA variable ufile |
| UnsafeUnpack.py:118:38:118:47 | ControlFlowNode for Attribute | UnsafeUnpack.py:120:41:120:58 | ControlFlowNode for uploaded_file_path |
@@ -50,6 +53,7 @@ nodes
| UnsafeUnpack.py:103:32:103:54 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| UnsafeUnpack.py:105:35:105:42 | ControlFlowNode for savepath | semmle.label | ControlFlowNode for savepath |
| UnsafeUnpack.py:108:22:108:34 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| UnsafeUnpack.py:108:22:108:48 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| UnsafeUnpack.py:112:35:112:43 | ControlFlowNode for file_path | semmle.label | ControlFlowNode for file_path |
| UnsafeUnpack.py:116:17:116:21 | SSA variable ufile | semmle.label | SSA variable ufile |
| UnsafeUnpack.py:116:27:116:39 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |

View File

@@ -3,19 +3,23 @@ edges
| csv_bad.py:9:19:9:25 | GSSA Variable request | csv_bad.py:16:16:16:22 | ControlFlowNode for request |
| csv_bad.py:9:19:9:25 | GSSA Variable request | csv_bad.py:24:16:24:22 | ControlFlowNode for request |
| csv_bad.py:16:16:16:22 | ControlFlowNode for request | csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute |
| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data |
| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data |
| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | csv_bad.py:16:16:16:38 | ControlFlowNode for Attribute() |
| csv_bad.py:16:16:16:38 | ControlFlowNode for Attribute() | csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data |
| csv_bad.py:16:16:16:38 | ControlFlowNode for Attribute() | csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data |
| csv_bad.py:24:16:24:22 | ControlFlowNode for request | csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute |
| csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data |
| csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute | csv_bad.py:24:16:24:38 | ControlFlowNode for Attribute() |
| csv_bad.py:24:16:24:38 | ControlFlowNode for Attribute() | csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data |
nodes
| csv_bad.py:9:19:9:25 | ControlFlowNode for ImportMember | semmle.label | ControlFlowNode for ImportMember |
| csv_bad.py:9:19:9:25 | GSSA Variable request | semmle.label | GSSA Variable request |
| csv_bad.py:16:16:16:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| csv_bad.py:16:16:16:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| csv_bad.py:16:16:16:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| csv_bad.py:18:24:18:31 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data |
| csv_bad.py:19:25:19:32 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data |
| csv_bad.py:24:16:24:22 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| csv_bad.py:24:16:24:27 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| csv_bad.py:24:16:24:38 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| csv_bad.py:25:46:25:53 | ControlFlowNode for csv_data | semmle.label | ControlFlowNode for csv_data |
subpaths
#select

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -3,22 +3,20 @@ import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
import semmle.python.ApiGraphs
class ApiUseTest extends InlineExpectationsTest {
ApiUseTest() { this = "ApiUseTest" }
override string getARelevantTag() { result = "use" }
module ApiUseTest implements TestSig {
string getARelevantTag() { result = "use" }
private predicate relevant_node(API::Node a, DataFlow::Node n, Location l) {
n = a.getAValueReachableFromSource() and l = n.getLocation()
}
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node n | this.relevant_node(_, n, location) |
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node n | relevant_node(_, n, location) |
tag = "use" and
// Only report the longest path on this line:
value =
max(API::Node a2, Location l2 |
this.relevant_node(a2, _, l2) and
relevant_node(a2, _, l2) and
l2.getFile() = location.getFile() and
l2.getStartLine() = location.getStartLine()
|
@@ -28,3 +26,5 @@ class ApiUseTest extends InlineExpectationsTest {
)
}
}
import MakeTest<ApiUseTest>

View File

@@ -1,2 +1,4 @@
failures
testFailures
| test.py:1:1:1:3 | foo | Tag mismatch: Actual result with tag 'foo' that is not part of getARelevantTag() |
| test.py:4:1:4:3 | foo | Tag mismatch: Actual result with tag 'foo' that is not part of getARelevantTag() |

View File

@@ -4,12 +4,10 @@
import python
import TestUtilities.InlineExpectationsTest
class MissingRelevantTag extends InlineExpectationsTest {
MissingRelevantTag() { this = "MissingRelevantTag" }
module MissingRelevantTag implements TestSig {
string getARelevantTag() { none() }
override string getARelevantTag() { none() }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Name name | name.getId() = "foo" |
location = name.getLocation() and
element = name.toString() and
@@ -18,3 +16,5 @@ class MissingRelevantTag extends InlineExpectationsTest {
)
}
}
import MakeTest<MissingRelevantTag>

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -2,12 +2,10 @@ import python
import semmle.python.essa.SsaCompute
import TestUtilities.InlineExpectationsTest
class UseTest extends InlineExpectationsTest {
UseTest() { this = "UseTest" }
module UseTest implements TestSig {
string getARelevantTag() { result in ["use-use", "def-use", "def"] }
override string getARelevantTag() { result in ["use-use", "def-use", "def"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(string name | name in ["x", "y"] |
exists(NameNode nodeTo, Location prevLoc |
@@ -39,3 +37,5 @@ class UseTest extends InlineExpectationsTest {
)
}
}
import MakeTest<UseTest>

View File

@@ -1,4 +1,4 @@
from flask import Flask, request
from flask import Flask, request, render_template_string, stream_template_string
app = Flask(__name__)
@app.route("/test_taint/<name>/<int:number>") # $routeSetup="/test_taint/<name>/<int:number>"
@@ -215,7 +215,34 @@ def test_taint(name = "World!", number="0", foo="foo"): # $requestHandler route
gd(), # $ tainted
)
# ----------------------------------
# non-request related taint-steps
# ----------------------------------
# render_template_string
source = TAINTED_STRING
ensure_tainted(source) # $ tainted
res = render_template_string(source)
ensure_tainted(res) # $ tainted
# since template variables are auto-escaped, we don't treat result as tainted
# see https://flask.palletsprojects.com/en/2.3.x/api/#flask.render_template_string
res = render_template_string("Hello {{ foo }}", foo=TAINTED_STRING)
ensure_not_tainted(res)
# stream_template_string
source = TAINTED_STRING
ensure_tainted(source) # $ tainted
res = stream_template_string(source)
for x in res:
ensure_tainted(x) # $ tainted
# since template variables are auto-escaped, we don't treat result as tainted
# see https://flask.palletsprojects.com/en/2.3.x/api/#flask.stream_template_string
res = stream_template_string("Hello {{ foo }}", foo=TAINTED_STRING)
for x in res:
ensure_not_tainted(x)
@app.route("/debug/<foo>/<bar>", methods=['GET']) # $routeSetup="/debug/<foo>/<bar>"

View File

@@ -3,12 +3,10 @@ private import semmle.python.dataflow.new.DataFlow
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
import TestUtilities.InlineExpectationsTest
class InlinePoorMansFunctionResolutionTest extends InlineExpectationsTest {
InlinePoorMansFunctionResolutionTest() { this = "InlinePoorMansFunctionResolutionTest" }
module InlinePoorMansFunctionResolutionTest implements TestSig {
string getARelevantTag() { result = "resolved" }
override string getARelevantTag() { result = "resolved" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(location.getFile().getRelativePath()) and
exists(Function func, DataFlow::Node ref |
ref = poorMansFunctionTracker(func) and
@@ -26,3 +24,5 @@ class InlinePoorMansFunctionResolutionTest extends InlineExpectationsTest {
)
}
}
import MakeTest<InlinePoorMansFunctionResolutionTest>

View File

@@ -1,6 +0,0 @@
WARNING: Module SensitiveData has been deprecated and may be removed in future (Sources.ql:4,6-19)
| test.py:16:1:16:14 | test.py:16 | a call returning a password |
| test.py:17:1:17:12 | test.py:17 | a call returning a password |
| test.py:18:1:18:12 | test.py:18 | a call returning a secret |
| test.py:19:1:19:19 | test.py:19 | a call returning a certificate or key |
| test.py:20:1:20:12 | test.py:20 | a call returning an ID |

View File

@@ -1,5 +0,0 @@
import python
import semmle.python.security.SensitiveData
from SensitiveData::Source src
select src.getLocation(), src.repr()

View File

@@ -1,21 +0,0 @@
from not_found import get_passwd, account_id
def get_password():
pass
def get_secret():
pass
def fetch_certificate():
pass
def encrypt_password(pwd):
pass
get_password()
get_passwd()
get_secret()
fetch_certificate()
account_id()
safe_to_store = encrypt_password(pwd)

View File

@@ -1,5 +0,0 @@
WARNING: Type HttpResponseTaintSink has been deprecated and may be removed in future (HttpResponseSinks.ql:5,6-27)
| test.py:9:12:9:26 | bottle handler function result | externally controlled string |
| test.py:13:12:13:24 | bottle handler function result | externally controlled string |
| test.py:19:12:19:33 | bottle handler function result | externally controlled string |
| test.py:36:21:36:51 | Taint sink | externally controlled string |

View File

@@ -1,7 +0,0 @@
import python
import semmle.python.web.HttpResponse
import semmle.python.security.strings.Untrusted
from HttpResponseTaintSink sink, TaintKind kind
where sink.sinks(kind)
select sink, kind

View File

@@ -1,9 +0,0 @@
WARNING: Type HttpRequestTaintSource has been deprecated and may be removed in future (HttpSources.ql:5,6-28)
| ../../../query-tests/Security/lib/bottle.py:64:11:64:24 | LocalRequest() | bottle.request |
| test.py:3:35:3:41 | ImportMember | bottle.request |
| test.py:8:11:8:14 | name | externally controlled string |
| test.py:12:9:12:12 | name | externally controlled string |
| test.py:18:12:18:18 | request | bottle.request |
| test.py:27:12:27:16 | where | externally controlled string |
| test.py:32:14:32:20 | request | bottle.request |
| test.py:36:34:36:40 | request | bottle.request |

View File

@@ -1,7 +0,0 @@
import python
import semmle.python.web.HttpRequest
import semmle.python.security.strings.Untrusted
from HttpRequestTaintSource source, TaintKind kind
where source.isSourceOf(kind)
select source.(ControlFlowNode).getNode(), kind

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