Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f4ea8bc

Browse files
author
Max Schaefer
committed
JavaScript: Introduce flow labels.
1 parent 4e4ef52 commit f4ea8bc

4 files changed

Lines changed: 157 additions & 53 deletions

File tree

javascript/ql/src/semmle/javascript/dataflow/Configuration.qll

Lines changed: 91 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,35 @@ abstract class Configuration extends string {
8888
/**
8989
* Holds if `source` is a relevant data flow source for this configuration.
9090
*/
91-
abstract predicate isSource(DataFlow::Node source);
91+
predicate isSource(DataFlow::Node source) {
92+
none()
93+
}
94+
95+
/**
96+
* Holds if `source` is a source of flow labelled with `lbl` that is relevant
97+
* for this configuration.
98+
*/
99+
predicate isSource(DataFlow::Node source, FlowLabel lbl) {
100+
none()
101+
}
92102

93103
/**
94104
* Holds if `sink` is a relevant data flow sink for this configuration.
95105
*/
96-
abstract predicate isSink(DataFlow::Node sink);
106+
predicate isSink(DataFlow::Node sink) {
107+
none()
108+
}
109+
110+
/**
111+
* Holds if `sink` is a sink of flow labelled with `lbl` that is relevant
112+
* for this configuration.
113+
*/
114+
predicate isSink(DataFlow::Node sink, FlowLabel lbl) {
115+
none()
116+
}
97117

98118
/**
99-
* Holds if `source -> sink` should be considered as a flow edge
119+
* Holds if `src -> trg` should be considered as a flow edge
100120
* in addition to standard data flow edges.
101121
*/
102122
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg) { none() }
@@ -105,14 +125,22 @@ abstract class Configuration extends string {
105125
* INTERNAL: This predicate should not normally be used outside the data flow
106126
* library.
107127
*
108-
* Holds if `source -> sink` should be considered as a flow edge
128+
* Holds if `src -> trg` should be considered as a flow edge
109129
* in addition to standard data flow edges, with `valuePreserving`
110130
* indicating whether the step preserves values or just taintedness.
111131
*/
112132
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg, boolean valuePreserving) {
113133
isAdditionalFlowStep(src, trg) and valuePreserving = true
114134
}
115135

136+
/**
137+
* Holds if `src -> trg` is a flow edge converting flow with label `inlbl` to
138+
* flow with label `outlbl`.
139+
*/
140+
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg, FlowLabel inlbl, FlowLabel outlbl) {
141+
none()
142+
}
143+
116144
/**
117145
* Holds if the intermediate flow node `node` is prohibited.
118146
*/
@@ -128,6 +156,11 @@ abstract class Configuration extends string {
128156
*/
129157
predicate isBarrier(DataFlow::Node src, DataFlow::Node trg) { none() }
130158

159+
/**
160+
* Holds if flow with label `lbl` cannot flow from `src` to `trg`.
161+
*/
162+
predicate isBarrier(DataFlow::Node src, DataFlow::Node trg, FlowLabel lbl) { none() }
163+
131164
/**
132165
* Holds if data flow node `guard` can act as a barrier when appearing
133166
* in a condition.
@@ -142,7 +175,7 @@ abstract class Configuration extends string {
142175
* Holds if data may flow from `source` to `sink` for this configuration.
143176
*/
144177
predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
145-
isSource(_, this) and isSink(_, this) and
178+
isSource(_, this, _) and isSink(_, this, _) and
146179
exists (SourcePathNode flowsource, SinkPathNode flowsink |
147180
hasPathFlow(flowsource, flowsink) and
148181
source = flowsource.getNode() and
@@ -176,6 +209,34 @@ abstract class Configuration extends string {
176209
}
177210
}
178211

212+
/**
213+
* A label describing the kind of information tracked by a flow configuration.
214+
*
215+
* There are two standard labels "data" and "taint", the former describing values
216+
* that directly originate from a flow source, the latter values that are derived
217+
* from a flow source via one or more transformations (such as string operations).
218+
*/
219+
abstract class FlowLabel extends string {
220+
bindingset[this] FlowLabel() { any() }
221+
}
222+
223+
module FlowLabel {
224+
private class StandardFlowLabel extends FlowLabel {
225+
StandardFlowLabel() { this = "data" or this = "taint" }
226+
}
227+
228+
/**
229+
* Gets the standard flow label for describing values that directly originate from a flow source.
230+
*/
231+
FlowLabel data() { result = "data" }
232+
233+
/**
234+
* Gets the standard flow label for describing values that are influenced ("tainted") by a flow
235+
* source, but not necessarily directly derived from it.
236+
*/
237+
FlowLabel taint() { result = "taint" }
238+
}
239+
179240
/**
180241
* A node that can act as a barrier when appearing in a condition.
181242
*
@@ -353,9 +414,10 @@ private predicate basicFlowStep(DataFlow::Node pred, DataFlow::Node succ, PathSu
353414
isRelevantForward(pred, cfg) and
354415
(
355416
// Local flow
356-
exists (boolean valuePreserving |
357-
localFlowStep(pred, succ, cfg, valuePreserving) and
358-
summary = PathSummary::level(valuePreserving)
417+
exists (FlowLabel predlbl, FlowLabel succlbl |
418+
localFlowStep(pred, succ, cfg, predlbl, succlbl) and
419+
not cfg.isBarrier(pred, succ, predlbl) and
420+
summary = MkPathSummary(false, false, predlbl, succlbl)
359421
)
360422
or
361423
// Flow through properties of objects
@@ -393,15 +455,21 @@ private predicate exploratoryFlowStep(DataFlow::Node pred, DataFlow::Node succ,
393455
/**
394456
* Holds if `nd` is a source node for configuration `cfg`.
395457
*/
396-
private predicate isSource(DataFlow::Node nd, DataFlow::Configuration cfg) {
397-
cfg.isSource(nd) or nd.(AdditionalSource).isSourceFor(cfg)
458+
private predicate isSource(DataFlow::Node nd, DataFlow::Configuration cfg, FlowLabel lbl) {
459+
(cfg.isSource(nd) or nd.(AdditionalSource).isSourceFor(cfg)) and
460+
lbl = FlowLabel::data()
461+
or
462+
cfg.isSource(nd, lbl)
398463
}
399464

400465
/**
401466
* Holds if `nd` is a sink node for configuration `cfg`.
402467
*/
403-
private predicate isSink(DataFlow::Node nd, DataFlow::Configuration cfg) {
404-
cfg.isSink(nd) or nd.(AdditionalSink).isSinkFor(cfg)
468+
private predicate isSink(DataFlow::Node nd, DataFlow::Configuration cfg, FlowLabel lbl) {
469+
(cfg.isSink(nd) or nd.(AdditionalSink).isSinkFor(cfg)) and
470+
lbl = any(FlowLabel f)
471+
or
472+
cfg.isSink(nd, lbl)
405473
}
406474

407475
/**
@@ -410,7 +478,7 @@ private predicate isSink(DataFlow::Node nd, DataFlow::Configuration cfg) {
410478
* No call/return matching is done, so this is a relatively coarse over-approximation.
411479
*/
412480
private predicate isRelevantForward(DataFlow::Node nd, DataFlow::Configuration cfg) {
413-
isSource(nd, cfg)
481+
isSource(nd, cfg, _)
414482
or
415483
exists (DataFlow::Node mid |
416484
isRelevantForward(mid, cfg) and exploratoryFlowStep(mid, nd, cfg)
@@ -424,7 +492,7 @@ private predicate isRelevantForward(DataFlow::Node nd, DataFlow::Configuration c
424492
*/
425493
private predicate isRelevant(DataFlow::Node nd, DataFlow::Configuration cfg) {
426494
isRelevantForward(nd, cfg) and
427-
isSink(nd, cfg)
495+
isSink(nd, cfg, _)
428496
or
429497
exists (DataFlow::Node mid |
430498
isRelevant(mid, cfg) and
@@ -527,7 +595,7 @@ private predicate reachableFromStoreBase(string prop, DataFlow::Node rhs, DataFl
527595
exists (DataFlow::Node mid, PathSummary oldSummary, PathSummary newSummary |
528596
reachableFromStoreBase(prop, rhs, mid, cfg, oldSummary) and
529597
flowStep(mid, cfg, nd, newSummary) and
530-
newSummary.valuePreserving() = true and
598+
newSummary.getEndLabel() = FlowLabel::data() and
531599
summary = oldSummary.append(newSummary)
532600
)
533601
}
@@ -586,9 +654,11 @@ private predicate flowsTo(PathNode flowsource, DataFlow::Node source,
586654
*/
587655
private predicate reachableFromSource(DataFlow::Node nd, DataFlow::Configuration cfg,
588656
PathSummary summary) {
589-
isSource(nd, cfg) and
590-
not cfg.isBarrier(nd) and
591-
summary = PathSummary::empty()
657+
exists (FlowLabel lbl |
658+
isSource(nd, cfg, lbl) and
659+
not cfg.isBarrier(nd) and
660+
summary = MkPathSummary(false, false, lbl, lbl)
661+
)
592662
or
593663
exists (DataFlow::Node pred, PathSummary oldSummary, PathSummary newSummary |
594664
reachableFromSource(pred, cfg, oldSummary) and
@@ -605,7 +675,7 @@ private predicate reachableFromSource(DataFlow::Node nd, DataFlow::Configuration
605675
private predicate onPath(DataFlow::Node nd, DataFlow::Configuration cfg,
606676
PathSummary summary1, PathSummary summary2) {
607677
reachableFromSource(nd, cfg, summary1) and
608-
isSink(nd, cfg) and
678+
isSink(nd, cfg, summary1.getEndLabel()) and
609679
not cfg.isBarrier(nd) and
610680
summary2 = PathSummary::empty()
611681
or
@@ -691,7 +761,7 @@ class PathNode extends TPathNode {
691761
*/
692762
class SourcePathNode extends PathNode {
693763
SourcePathNode() {
694-
isSource(nd, cfg)
764+
isSource(nd, cfg, _)
695765
}
696766
}
697767

@@ -700,7 +770,7 @@ class SourcePathNode extends PathNode {
700770
*/
701771
class SinkPathNode extends PathNode {
702772
SinkPathNode() {
703-
isSink(nd, cfg)
773+
isSink(nd, cfg, _)
704774
}
705775
}
706776

javascript/ql/src/semmle/javascript/dataflow/TaintTracking.qll

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,19 @@ module TaintTracking {
3838
* The smaller this predicate is, the faster `hasFlow()` will converge.
3939
*/
4040
// overridden to provide taint-tracking specific qldoc
41-
abstract override predicate isSource(DataFlow::Node source);
41+
override predicate isSource(DataFlow::Node source) {
42+
super.isSource(source)
43+
}
4244

4345
/**
4446
* Holds if `sink` is a relevant taint sink.
4547
*
4648
* The smaller this predicate is, the faster `hasFlow()` will converge.
4749
*/
4850
// overridden to provide taint-tracking specific qldoc
49-
abstract override predicate isSink(DataFlow::Node sink);
51+
override predicate isSink(DataFlow::Node sink) {
52+
super.isSink(sink)
53+
}
5054

5155
/** Holds if the intermediate node `node` is a taint sanitizer. */
5256
predicate isSanitizer(DataFlow::Node node) {
@@ -58,6 +62,11 @@ module TaintTracking {
5862
none()
5963
}
6064

65+
/** Holds if the edge from `source` to `sink` is a taint sanitizer for data labelled with `lbl`. */
66+
predicate isSanitizer(DataFlow::Node source, DataFlow::Node sink, DataFlow::FlowLabel lbl) {
67+
none()
68+
}
69+
6170
/**
6271
* Holds if data flow node `guard` can act as a sanitizer when appearing
6372
* in a condition.
@@ -82,6 +91,12 @@ module TaintTracking {
8291
isSanitizer(source, sink)
8392
}
8493

94+
final
95+
override predicate isBarrier(DataFlow::Node source, DataFlow::Node sink, DataFlow::FlowLabel lbl) {
96+
super.isBarrier(source, sink, lbl) or
97+
isSanitizer(source, sink, lbl)
98+
}
99+
85100
final
86101
override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) {
87102
super.isBarrierGuard(guard) or

0 commit comments

Comments
 (0)