Skip to content

Commit ba60399

Browse files
committed
Go: Add alert provenance plumbing.
1 parent 004bda1 commit ba60399

File tree

8 files changed

+108
-68
lines changed

8 files changed

+108
-68
lines changed

go/ql/lib/semmle/go/dataflow/ExternalFlow.qll

Lines changed: 61 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ private import codeql.mad.ModelValidation as SharedModelVal
8282

8383
/** Holds if `package` have MaD framework coverage. */
8484
private predicate packageHasMaDCoverage(string package) {
85-
sourceModel(package, _, _, _, _, _, _, _, _) or
86-
sinkModel(package, _, _, _, _, _, _, _, _) or
87-
summaryModel(package, _, _, _, _, _, _, _, _, _)
85+
sourceModel(package, _, _, _, _, _, _, _, _, _) or
86+
sinkModel(package, _, _, _, _, _, _, _, _, _) or
87+
summaryModel(package, _, _, _, _, _, _, _, _, _, _)
8888
}
8989

9090
/**
@@ -128,23 +128,24 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
128128
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
129129
string ext, string output, string provenance |
130130
canonicalPackageHasASubpackage(package, subpkg) and
131-
sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, provenance)
131+
sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, provenance, _)
132132
)
133133
or
134134
part = "sink" and
135135
n =
136136
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
137137
string ext, string input, string provenance |
138138
canonicalPackageHasASubpackage(package, subpkg) and
139-
sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, provenance)
139+
sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, provenance, _)
140140
)
141141
or
142142
part = "summary" and
143143
n =
144144
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
145145
string ext, string input, string output, string provenance |
146146
canonicalPackageHasASubpackage(package, subpkg) and
147-
summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, provenance)
147+
summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, provenance,
148+
_)
148149
)
149150
)
150151
}
@@ -153,9 +154,9 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
153154
module ModelValidation {
154155
private string getInvalidModelInput() {
155156
exists(string pred, AccessPath input, string part |
156-
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
157+
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
157158
or
158-
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
159+
summaryModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "summary"
159160
|
160161
(
161162
invalidSpecComponent(input, part) and
@@ -171,9 +172,9 @@ module ModelValidation {
171172

172173
private string getInvalidModelOutput() {
173174
exists(string pred, string output, string part |
174-
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
175+
sourceModel(_, _, _, _, _, _, output, _, _, _) and pred = "source"
175176
or
176-
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
177+
summaryModel(_, _, _, _, _, _, _, output, _, _, _) and pred = "summary"
177178
|
178179
invalidSpecComponent(output, part) and
179180
not part = "" and
@@ -183,11 +184,11 @@ module ModelValidation {
183184
}
184185

185186
private module KindValConfig implements SharedModelVal::KindValidationConfigSig {
186-
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) }
187+
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _, _) }
187188

188-
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) }
189+
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _, _) }
189190

190-
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) }
191+
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _, _) }
191192
}
192193

193194
private module KindVal = SharedModelVal::KindValidation<KindValConfig>;
@@ -197,11 +198,12 @@ module ModelValidation {
197198
string pred, string package, string type, string name, string signature, string ext,
198199
string provenance
199200
|
200-
sourceModel(package, type, _, name, signature, ext, _, _, provenance) and pred = "source"
201+
sourceModel(package, type, _, name, signature, ext, _, _, provenance, _) and pred = "source"
201202
or
202-
sinkModel(package, type, _, name, signature, ext, _, _, provenance) and pred = "sink"
203+
sinkModel(package, type, _, name, signature, ext, _, _, provenance, _) and pred = "sink"
203204
or
204-
summaryModel(package, type, _, name, signature, ext, _, _, _, provenance) and pred = "summary"
205+
summaryModel(package, type, _, name, signature, ext, _, _, _, provenance, _) and
206+
pred = "summary"
205207
|
206208
not package.replaceAll("$ANYVERSION", "").regexpMatch("[a-zA-Z0-9_\\./-]*") and
207209
result = "Dubious package \"" + package + "\" in " + pred + " model."
@@ -237,9 +239,9 @@ pragma[nomagic]
237239
private predicate elementSpec(
238240
string package, string type, boolean subtypes, string name, string signature, string ext
239241
) {
240-
sourceModel(package, type, subtypes, name, signature, ext, _, _, _) or
241-
sinkModel(package, type, subtypes, name, signature, ext, _, _, _) or
242-
summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _)
242+
sourceModel(package, type, subtypes, name, signature, ext, _, _, _, _) or
243+
sinkModel(package, type, subtypes, name, signature, ext, _, _, _, _) or
244+
summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _, _)
243245
}
244246

245247
private string paramsStringPart(Function f, int i) {
@@ -297,8 +299,8 @@ predicate hasExternalSpecification(Function f) {
297299
f = any(SummarizedCallable sc).asFunction()
298300
or
299301
exists(SourceSinkInterpretationInput::SourceOrSinkElement e | f = e.asEntity() |
300-
SourceSinkInterpretationInput::sourceElement(e, _, _, _) or
301-
SourceSinkInterpretationInput::sinkElement(e, _, _, _)
302+
SourceSinkInterpretationInput::sourceElement(e, _, _, _, _) or
303+
SourceSinkInterpretationInput::sinkElement(e, _, _, _, _)
302304
)
303305
}
304306

@@ -351,9 +353,9 @@ private module Cached {
351353
* model.
352354
*/
353355
cached
354-
predicate sourceNode(DataFlow::Node node, string kind) {
356+
predicate sourceNode(DataFlow::Node node, string kind, string model) {
355357
exists(SourceSinkInterpretationInput::InterpretNode n |
356-
isSourceNode(n, kind) and n.asNode() = node
358+
isSourceNode(n, kind, model) and n.asNode() = node
357359
)
358360
}
359361

@@ -362,57 +364,78 @@ private module Cached {
362364
* model.
363365
*/
364366
cached
365-
predicate sinkNode(DataFlow::Node node, string kind) {
367+
predicate sinkNode(DataFlow::Node node, string kind, string model) {
366368
exists(SourceSinkInterpretationInput::InterpretNode n |
367-
isSinkNode(n, kind) and n.asNode() = node
369+
isSinkNode(n, kind, model) and n.asNode() = node
368370
)
369371
}
370372
}
371373

372374
import Cached
373375

376+
/**
377+
* Holds if `node` is specified as a source with the given kind in a MaD flow
378+
* model.
379+
*/
380+
predicate sourceNode(DataFlow::Node node, string kind) { sourceNode(node, kind, _) }
381+
382+
/**
383+
* Holds if `node` is specified as a sink with the given kind in a MaD flow
384+
* model.
385+
*/
386+
predicate sinkNode(DataFlow::Node node, string kind) { sinkNode(node, kind, _) }
387+
374388
private predicate interpretSummary(
375-
Callable c, string input, string output, string kind, string provenance
389+
Callable c, string input, string output, string kind, string provenance, string model
376390
) {
377391
exists(
378-
string namespace, string type, boolean subtypes, string name, string signature, string ext
392+
string namespace, string type, boolean subtypes, string name, string signature, string ext,
393+
QlBuiltins::ExtensionId madId
379394
|
380-
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
395+
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance,
396+
madId) and
397+
model = "MaD:" + madId.toString() and
381398
c.asFunction() = interpretElement(namespace, type, subtypes, name, signature, ext).asEntity()
382399
)
383400
}
384401

385402
// adapter class for converting Mad summaries to `SummarizedCallable`s
386403
private class SummarizedCallableAdapter extends SummarizedCallable {
387-
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _) }
404+
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _, _) }
388405

389-
private predicate relevantSummaryElementManual(string input, string output, string kind) {
406+
private predicate relevantSummaryElementManual(
407+
string input, string output, string kind, string model
408+
) {
390409
exists(Provenance provenance |
391-
interpretSummary(this, input, output, kind, provenance) and
410+
interpretSummary(this, input, output, kind, provenance, model) and
392411
provenance.isManual()
393412
)
394413
}
395414

396-
private predicate relevantSummaryElementGenerated(string input, string output, string kind) {
415+
private predicate relevantSummaryElementGenerated(
416+
string input, string output, string kind, string model
417+
) {
397418
exists(Provenance provenance |
398-
interpretSummary(this, input, output, kind, provenance) and
419+
interpretSummary(this, input, output, kind, provenance, model) and
399420
provenance.isGenerated()
400421
)
401422
}
402423

403-
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
424+
override predicate propagatesFlow(
425+
string input, string output, boolean preservesValue, string model
426+
) {
404427
exists(string kind |
405-
this.relevantSummaryElementManual(input, output, kind)
428+
this.relevantSummaryElementManual(input, output, kind, model)
406429
or
407-
not this.relevantSummaryElementManual(_, _, _) and
408-
this.relevantSummaryElementGenerated(input, output, kind)
430+
not this.relevantSummaryElementManual(_, _, _, _) and
431+
this.relevantSummaryElementGenerated(input, output, kind, model)
409432
|
410433
if kind = "value" then preservesValue = true else preservesValue = false
411434
)
412435
}
413436

414437
override predicate hasProvenance(Provenance provenance) {
415-
interpretSummary(this, _, _, _, provenance)
438+
interpretSummary(this, _, _, _, provenance, _)
416439
}
417440
}
418441

go/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ private import DataFlowImplCommon
44
private import ContainerFlow
55
private import FlowSummaryImpl as FlowSummaryImpl
66
private import semmle.go.dataflow.FlowSummary as FlowSummary
7+
private import semmle.go.dataflow.ExternalFlow
78
private import codeql.util.Unit
89
import DataFlowNodes::Private
910

@@ -410,6 +411,10 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { no
410411
/** Extra data-flow steps needed for lambda flow analysis. */
411412
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
412413

414+
predicate knownSourceModel(Node source, string model) { sourceNode(source, _, model) }
415+
416+
predicate knownSinkModel(Node sink, string model) { sinkNode(sink, _, model) }
417+
413418
/**
414419
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
415420
* side-effect, resulting in a summary from `p` to itself.

go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ predicate isReturnedWithError(Node node) {
104104
* (intra-procedural) step.
105105
*/
106106
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
107-
simpleLocalFlowStep(nodeFrom, nodeTo)
107+
simpleLocalFlowStep(nodeFrom, nodeTo, _)
108108
or
109109
// Simple flow through library code is included in the exposed local
110110
// step relation, even though flow is technically inter-procedural
@@ -118,14 +118,16 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) {
118118
* data flow. It may have less flow than the `localFlowStep` predicate.
119119
*/
120120
cached
121-
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
122-
basicLocalFlowStep(nodeFrom, nodeTo)
121+
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
122+
basicLocalFlowStep(nodeFrom, nodeTo) and
123+
model = ""
123124
or
124125
// step through function model
125-
any(FunctionModel m).flowStep(nodeFrom, nodeTo)
126+
any(FunctionModel m).flowStep(nodeFrom, nodeTo) and
127+
model = "FunctionModel"
126128
or
127129
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
128-
nodeTo.(FlowSummaryNode).getSummaryNode(), true)
130+
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
129131
}
130132

131133
/**

go/ql/lib/semmle/go/dataflow/internal/ExternalFlowExtensions.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@
77
*/
88
extensible predicate sourceModel(
99
string package, string type, boolean subtypes, string name, string signature, string ext,
10-
string output, string kind, string provenance
10+
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
1111
);
1212

1313
/**
1414
* Holds if a sink model exists for the given parameters.
1515
*/
1616
extensible predicate sinkModel(
1717
string package, string type, boolean subtypes, string name, string signature, string ext,
18-
string input, string kind, string provenance
18+
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
1919
);
2020

2121
/**
2222
* Holds if a summary model exists for the given parameters.
2323
*/
2424
extensible predicate summaryModel(
2525
string package, string type, boolean subtypes, string name, string signature, string ext,
26-
string input, string output, string kind, string provenance
26+
string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
2727
);

go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,14 @@ module SourceSinkInterpretationInput implements
104104
* `output`, kind `kind`, and provenance `provenance`.
105105
*/
106106
predicate sourceElement(
107-
SourceOrSinkElement e, string output, string kind, Public::Provenance provenance
107+
SourceOrSinkElement e, string output, string kind, Public::Provenance provenance, string model
108108
) {
109109
exists(
110-
string package, string type, boolean subtypes, string name, string signature, string ext
110+
string package, string type, boolean subtypes, string name, string signature, string ext,
111+
QlBuiltins::ExtensionId madId
111112
|
112-
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance) and
113+
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance, madId) and
114+
model = "MaD:" + madId.toString() and
113115
e = interpretElement(package, type, subtypes, name, signature, ext)
114116
)
115117
}
@@ -119,12 +121,14 @@ module SourceSinkInterpretationInput implements
119121
* `input`, kind `kind` and provenance `provenance`.
120122
*/
121123
predicate sinkElement(
122-
SourceOrSinkElement e, string input, string kind, Public::Provenance provenance
124+
SourceOrSinkElement e, string input, string kind, Public::Provenance provenance, string model
123125
) {
124126
exists(
125-
string package, string type, boolean subtypes, string name, string signature, string ext
127+
string package, string type, boolean subtypes, string name, string signature, string ext,
128+
QlBuiltins::ExtensionId madId
126129
|
127-
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
130+
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, madId) and
131+
model = "MaD:" + madId.toString() and
128132
e = interpretElement(package, type, subtypes, name, signature, ext)
129133
)
130134
}

go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ predicate localExprTaint(Expr src, Expr sink) {
2828
*/
2929
predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
3030
DataFlow::localFlowStep(src, sink) or
31-
localAdditionalTaintStep(src, sink) or
31+
localAdditionalTaintStep(src, sink, _) or
3232
// Simple flow through library code is included in the exposed local
3333
// step relation, even though flow is technically inter-procedural
3434
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(src, sink, _)
@@ -86,18 +86,24 @@ class AdditionalTaintStep extends Unit {
8686
* Holds if the additional step from `pred` to `succ` should be included in all
8787
* global taint flow configurations.
8888
*/
89-
predicate localAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
90-
referenceStep(pred, succ) or
91-
elementWriteStep(pred, succ) or
92-
fieldReadStep(pred, succ) or
93-
elementStep(pred, succ) or
94-
tupleStep(pred, succ) or
95-
stringConcatStep(pred, succ) or
96-
sliceStep(pred, succ) or
97-
any(FunctionModel fm).taintStep(pred, succ) or
98-
any(AdditionalTaintStep a).step(pred, succ) or
89+
predicate localAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ, string model) {
90+
(
91+
referenceStep(pred, succ) or
92+
elementWriteStep(pred, succ) or
93+
fieldReadStep(pred, succ) or
94+
elementStep(pred, succ) or
95+
tupleStep(pred, succ) or
96+
stringConcatStep(pred, succ) or
97+
sliceStep(pred, succ)
98+
) and
99+
model = ""
100+
or
101+
any(FunctionModel fm).taintStep(pred, succ) and model = "FunctionModel"
102+
or
103+
any(AdditionalTaintStep a).step(pred, succ) and model = "AdditionalTaintStep"
104+
or
99105
FlowSummaryImpl::Private::Steps::summaryLocalStep(pred.(DataFlowPrivate::FlowSummaryNode)
100-
.getSummaryNode(), succ.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false)
106+
.getSummaryNode(), succ.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false, model)
101107
}
102108

103109
/**
@@ -207,8 +213,8 @@ abstract class FunctionModel extends Function {
207213
* Holds if the additional step from `src` to `sink` should be included in all
208214
* global taint flow configurations.
209215
*/
210-
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
211-
localAdditionalTaintStep(src, sink)
216+
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, string model) {
217+
localAdditionalTaintStep(src, sink, model)
212218
}
213219

214220
/**

0 commit comments

Comments
 (0)