Skip to content

Commit acb1191

Browse files
committed
Python: Add alert provenance plumbing.
1 parent cb97b10 commit acb1191

File tree

11 files changed

+126
-76
lines changed

11 files changed

+126
-76
lines changed

python/ql/lib/semmle/python/dataflow/new/FlowSummary.qll

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,22 @@ abstract class SummarizedCallable extends LibraryCallable, Impl::Public::Summari
3131
* DEPRECATED: Use `propagatesFlow` instead.
3232
*/
3333
deprecated predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
34-
this.propagatesFlow(input, output, preservesValue)
34+
this.propagatesFlow(input, output, preservesValue, _)
3535
}
36+
37+
override predicate propagatesFlow(
38+
string input, string output, boolean preservesValue, string model
39+
) {
40+
this.propagatesFlow(input, output, preservesValue) and model = this
41+
}
42+
43+
/**
44+
* Holds if data may flow from `input` to `output` through this callable.
45+
*
46+
* `preservesValue` indicates whether this is a value-preserving step or a taint-step.
47+
*/
48+
predicate propagatesFlow(string input, string output, boolean preservesValue) { none() }
49+
3650
}
3751

3852
deprecated class RequiredSummaryComponentStack = Impl::Private::RequiredSummaryComponentStack;
@@ -42,7 +56,7 @@ private class SummarizedCallableFromModel extends SummarizedCallable {
4256
string path;
4357

4458
SummarizedCallableFromModel() {
45-
ModelOutput::relevantSummaryModel(type, path, _, _, _) and
59+
ModelOutput::relevantSummaryModel(type, path, _, _, _, _) and
4660
this = type + ";" + path
4761
}
4862

@@ -55,8 +69,8 @@ private class SummarizedCallableFromModel extends SummarizedCallable {
5569
)
5670
}
5771

58-
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
59-
exists(string kind | ModelOutput::relevantSummaryModel(type, path, input, output, kind) |
72+
override predicate propagatesFlow(string input, string output, boolean preservesValue, string model) {
73+
exists(string kind | ModelOutput::relevantSummaryModel(type, path, input, output, kind, model) |
6074
kind = "value" and
6175
preservesValue = true
6276
or

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ private import DataFlowPublic
33
private import semmle.python.essa.SsaCompute
44
private import semmle.python.dataflow.new.internal.ImportResolution
55
private import FlowSummaryImpl as FlowSummaryImpl
6+
private import semmle.python.frameworks.data.ModelsAsData
67
// Since we allow extra data-flow steps from modeled frameworks, we import these
78
// up-front, to ensure these are included. This provides a more seamless experience from
89
// a user point of view, since they don't need to know they need to import a specific
@@ -471,12 +472,12 @@ import StepRelationTransformations
471472
*
472473
* It includes flow steps from flow summaries.
473474
*/
474-
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
475-
simpleLocalFlowStepForTypetracking(nodeFrom, nodeTo)
475+
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
476+
simpleLocalFlowStepForTypetracking(nodeFrom, nodeTo) and model = ""
476477
or
477-
summaryFlowSteps(nodeFrom, nodeTo)
478+
summaryLocalStep(nodeFrom, nodeTo, model)
478479
or
479-
variableCaptureLocalFlowStep(nodeFrom, nodeTo)
480+
variableCaptureLocalFlowStep(nodeFrom, nodeTo) and model = ""
480481
}
481482

482483
/**
@@ -490,13 +491,9 @@ predicate simpleLocalFlowStepForTypetracking(Node nodeFrom, Node nodeTo) {
490491
LocalFlow::localFlowStep(nodeFrom, nodeTo)
491492
}
492493

493-
private predicate summaryLocalStep(Node nodeFrom, Node nodeTo) {
494+
private predicate summaryLocalStep(Node nodeFrom, Node nodeTo, string model) {
494495
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
495-
nodeTo.(FlowSummaryNode).getSummaryNode(), true)
496-
}
497-
498-
predicate summaryFlowSteps(Node nodeFrom, Node nodeTo) {
499-
IncludePostUpdateFlow<PhaseDependentFlow<summaryLocalStep/2>::step/2>::step(nodeFrom, nodeTo)
496+
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
500497
}
501498

502499
predicate variableCaptureLocalFlowStep(Node nodeFrom, Node nodeTo) {
@@ -1057,6 +1054,14 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
10571054
/** Extra data-flow steps needed for lambda flow analysis. */
10581055
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
10591056

1057+
predicate knownSourceModel(Node source, string model) {
1058+
source = ModelOutput::getASourceNode(_, model).asSource()
1059+
}
1060+
1061+
predicate knownSinkModel(Node sink, string model) {
1062+
sink = ModelOutput::getASinkNode(_, model).asSink()
1063+
}
1064+
10601065
/**
10611066
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
10621067
* side-effect, resulting in a summary from `p` to itself.

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ newtype TContent =
632632
or
633633
//
634634
// 2) summaries in data-extension files
635-
exists(string input, string output | ModelOutput::relevantSummaryModel(_, _, input, output, _) |
635+
exists(string input, string output | ModelOutput::relevantSummaryModel(_, _, input, output, _, _) |
636636
attr = [input, output].regexpFind("(?<=(^|\\.)Attribute\\[)[^\\]]+(?=\\])", _, _).trim()
637637
)
638638
} or

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowUtil.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ private import FlowSummaryImpl as FlowSummaryImpl
1212
* (intra-procedural) step.
1313
*/
1414
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
15-
simpleLocalFlowStep(nodeFrom, nodeTo)
15+
simpleLocalFlowStep(nodeFrom, nodeTo, _)
1616
or
1717
// Simple flow through library code is included in the exposed local
1818
// step relation, even though flow is technically inter-procedural.

python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ private module Cached {
242242
*/
243243
pragma[nomagic]
244244
private predicate localSourceFlowStep(Node nodeFrom, Node nodeTo) {
245-
simpleLocalFlowStep(nodeFrom, nodeTo) and
245+
simpleLocalFlowStep(nodeFrom, nodeTo, _) and
246246
not nodeTo = any(ModuleVariableNode v).getARead()
247247
}
248248

python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPrivate.qll

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ private module Cached {
2424
* global taint flow configurations.
2525
*/
2626
cached
27-
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
28-
localAdditionalTaintStep(nodeFrom, nodeTo)
27+
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
28+
localAdditionalTaintStep(nodeFrom, nodeTo, model)
2929
or
30-
any(AdditionalTaintStep a).step(nodeFrom, nodeTo)
30+
any(AdditionalTaintStep a).step(nodeFrom, nodeTo) and
31+
model = "AdditionalTaintStep"
3132
}
3233

3334
/**
@@ -36,30 +37,34 @@ private module Cached {
3637
* different objects.
3738
*/
3839
cached
39-
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
40-
concatStep(nodeFrom, nodeTo)
41-
or
42-
subscriptStep(nodeFrom, nodeTo)
43-
or
44-
stringManipulation(nodeFrom, nodeTo)
45-
or
46-
containerStep(nodeFrom, nodeTo)
47-
or
48-
copyStep(nodeFrom, nodeTo)
49-
or
50-
DataFlowPrivate::forReadStep(nodeFrom, _, nodeTo)
51-
or
52-
DataFlowPrivate::iterableUnpackingReadStep(nodeFrom, _, nodeTo)
53-
or
54-
DataFlowPrivate::iterableUnpackingStoreStep(nodeFrom, _, nodeTo)
55-
or
56-
awaitStep(nodeFrom, nodeTo)
57-
or
58-
asyncWithStep(nodeFrom, nodeTo)
40+
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
41+
(
42+
concatStep(nodeFrom, nodeTo)
43+
or
44+
subscriptStep(nodeFrom, nodeTo)
45+
or
46+
stringManipulation(nodeFrom, nodeTo)
47+
or
48+
containerStep(nodeFrom, nodeTo)
49+
or
50+
copyStep(nodeFrom, nodeTo)
51+
or
52+
DataFlowPrivate::forReadStep(nodeFrom, _, nodeTo)
53+
or
54+
DataFlowPrivate::iterableUnpackingReadStep(nodeFrom, _, nodeTo)
55+
or
56+
DataFlowPrivate::iterableUnpackingStoreStep(nodeFrom, _, nodeTo)
57+
or
58+
awaitStep(nodeFrom, nodeTo)
59+
or
60+
asyncWithStep(nodeFrom, nodeTo)
61+
) and
62+
model = ""
5963
or
6064
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom
6165
.(DataFlowPrivate::FlowSummaryNode)
62-
.getSummaryNode(), nodeTo.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false)
66+
.getSummaryNode(), nodeTo.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false,
67+
model)
6368
}
6469
}
6570

python/ql/lib/semmle/python/dataflow/new/internal/TaintTrackingPublic.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
3434
// Ordinary data flow
3535
DataFlow::localFlowStep(nodeFrom, nodeTo)
3636
or
37-
localAdditionalTaintStep(nodeFrom, nodeTo)
37+
localAdditionalTaintStep(nodeFrom, nodeTo, _)
3838
}
3939

4040
/**

python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,15 @@ private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
2323
ContentFilter getFilterFromWithContentStep(Content content) { none() }
2424

2525
// Callables
26-
class SummarizedCallable = FlowSummaryImpl::Private::SummarizedCallableImpl;
26+
class SummarizedCallable instanceof FlowSummaryImpl::Private::SummarizedCallableImpl {
27+
string toString() { result = super.toString() }
28+
29+
predicate propagatesFlow(
30+
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
31+
) {
32+
super.propagatesFlow(input, output, preservesValue, _)
33+
}
34+
}
2735

2836
// Summaries and their stacks
2937
class SummaryComponent = FlowSummaryImpl::Private::SummaryComponent;

0 commit comments

Comments
 (0)