Skip to content

Commit 729efff

Browse files
authored
Merge pull request github#18265 from asgerf/jss/flow-labels2
JS: Migrate all queries to proper flow states and deprecate FlowLabel
2 parents a53d294 + e5ae7e0 commit 729efff

File tree

77 files changed

+1135
-653
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+1135
-653
lines changed

docs/codeql/codeql-language-guides/analyzing-data-flow-in-javascript-and-typescript.rst

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,11 @@ additional taint step from the first argument of ``resolveSymlinks`` to its resu
416416
417417
// ...
418418
419-
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
419+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
420420
exists(DataFlow::CallNode c |
421421
c = DataFlow::moduleImport("resolve-symlinks").getACall() and
422-
pred = c.getArgument(0) and
423-
succ = c
422+
node1 = c.getArgument(0) and
423+
node2 = c
424424
)
425425
}
426426
}
@@ -431,11 +431,11 @@ to wrap it in a new subclass of ``TaintTracking::SharedTaintStep`` like this:
431431
.. code-block:: ql
432432
433433
class StepThroughResolveSymlinks extends TaintTracking::SharedTaintStep {
434-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
434+
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
435435
exists(DataFlow::CallNode c |
436436
c = DataFlow::moduleImport("resolve-symlinks").getACall() and
437-
pred = c.getArgument(0) and
438-
succ = c
437+
node1 = c.getArgument(0) and
438+
node2 = c
439439
)
440440
}
441441
}

javascript/ql/examples/queries/dataflow/BackendIdor/BackendIdor.ql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ module IdorTaintConfig implements DataFlow::ConfigSig {
1818

1919
predicate isSink(DataFlow::Node node) { exists(ClientRequest req | node = req.getADataNode()) }
2020

21-
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
21+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
2222
// Step from x -> { userId: x }
23-
succ.(DataFlow::SourceNode).getAPropertyWrite("userId").getRhs() = pred
23+
node2.(DataFlow::SourceNode).getAPropertyWrite("userId").getRhs() = node1
2424
}
2525

2626
predicate isBarrier(DataFlow::Node node) {

javascript/ql/examples/queries/dataflow/InformationDisclosure/InformationDisclosure.ql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@ module AuthKeyTrackingConfig implements DataFlow::ConfigSig {
3737
)
3838
}
3939

40-
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
40+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
4141
// Step into objects: x -> { f: x }
42-
succ.(DataFlow::SourceNode).getAPropertyWrite().getRhs() = pred
42+
node2.(DataFlow::SourceNode).getAPropertyWrite().getRhs() = node1
4343
or
4444
// Step through JSON serialization: x -> JSON.stringify(x)
4545
// Note: TaintTracking::Configuration includes this step by default, but not DataFlow::Configuration
4646
exists(DataFlow::CallNode call |
4747
call = DataFlow::globalVarRef("JSON").getAMethodCall("stringify") and
48-
pred = call.getArgument(0) and
49-
succ = call
48+
node1 = call.getArgument(0) and
49+
node2 = call
5050
)
5151
}
5252
}

javascript/ql/lib/semmle/javascript/dataflow/AdditionalFlowSteps.qll

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,12 @@ class LegacyFlowStep extends Unit {
147147
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
148148

149149
/**
150+
* DEPRECATED. The `FlowLabel` class and steps involving flow labels are no longer used by any queries.
151+
*
150152
* Holds if `pred` → `succ` should be considered a data flow edge
151153
* transforming values with label `predlbl` to have label `succlbl`.
152154
*/
153-
predicate step(
155+
deprecated predicate step(
154156
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
155157
DataFlow::FlowLabel succlbl
156158
) {
@@ -199,11 +201,13 @@ module LegacyFlowStep {
199201
}
200202

201203
/**
204+
* DEPRECATED. The `FlowLabel` class and steps involving flow labels are no longer used by any queries.
205+
*
202206
* Holds if `pred` → `succ` should be considered a data flow edge
203207
* transforming values with label `predlbl` to have label `succlbl`.
204208
*/
205209
cached
206-
predicate step(
210+
deprecated predicate step(
207211
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
208212
DataFlow::FlowLabel succlbl
209213
) {
@@ -273,10 +277,12 @@ class SharedFlowStep extends Unit {
273277
predicate step(DataFlow::Node pred, DataFlow::Node succ) { none() }
274278

275279
/**
280+
* DEPRECATED. The `FlowLabel` class and steps involving flow labels are no longer used by any queries.
281+
*
276282
* Holds if `pred` → `succ` should be considered a data flow edge
277283
* transforming values with label `predlbl` to have label `succlbl`.
278284
*/
279-
predicate step(
285+
deprecated predicate step(
280286
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
281287
DataFlow::FlowLabel succlbl
282288
) {
@@ -353,10 +359,12 @@ module SharedFlowStep {
353359

354360
// The following are aliases for old step predicates that have no corresponding predicate in AdditionalFlowStep
355361
/**
362+
* DEPRECATED. The `FlowLabel` class and steps involving flow labels are no longer used by any queries.
363+
*
356364
* Holds if `pred` → `succ` should be considered a data flow edge
357365
* transforming values with label `predlbl` to have label `succlbl`.
358366
*/
359-
predicate step(
367+
deprecated predicate step(
360368
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel predlbl,
361369
DataFlow::FlowLabel succlbl
362370
) {

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,9 @@ deprecated private predicate isBarrierGuardInternal(
295295
}
296296

297297
/**
298+
* DEPRECATED. Use a query-specific `FlowState` class instead.
299+
* See [guide on using flow state](https://codeql.github.com/docs/codeql-language-guides/using-flow-labels-for-precise-data-flow-analysis) for more details.
300+
*
298301
* A label describing the kind of information tracked by a flow configuration.
299302
*
300303
* There are two standard labels "data" and "taint".
@@ -303,7 +306,7 @@ deprecated private predicate isBarrierGuardInternal(
303306
* - "taint" additionally permits flow through transformations such as string operations,
304307
* and is the default flow source for a `TaintTracking::Configuration`.
305308
*/
306-
abstract class FlowLabel extends string {
309+
abstract deprecated class FlowLabel extends string {
307310
bindingset[this]
308311
FlowLabel() { any() }
309312

@@ -341,7 +344,7 @@ deprecated class StandardFlowLabel extends FlowLabel {
341344
StandardFlowLabel() { this = "data" or this = "taint" }
342345
}
343346

344-
module FlowLabel {
347+
deprecated module FlowLabel {
345348
/**
346349
* Gets the standard flow label for describing values that directly originate from a flow source.
347350
*/

javascript/ql/lib/semmle/javascript/dataflow/internal/BarrierGuards.qll

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,19 @@ module MakeBarrierGuard<BarrierGuardSig BaseGuard> {
3636
}
3737
}
3838

39-
private signature class LabeledBarrierGuardSig extends DataFlow::Node {
40-
/**
41-
* Holds if this node acts as a barrier for `label`, blocking further flow from `e` if `this` evaluates to `outcome`.
42-
*/
43-
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label);
39+
deprecated private module DeprecationWrapper {
40+
signature class LabeledBarrierGuardSig extends DataFlow::Node {
41+
/**
42+
* Holds if this node acts as a barrier for `label`, blocking further flow from `e` if `this` evaluates to `outcome`.
43+
*/
44+
predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label);
45+
}
4446
}
4547

4648
/**
4749
* Converts a barrier guard class to a set of nodes to include in an implementation of `isBarrier(node, label)`.
4850
*/
49-
module MakeLabeledBarrierGuard<LabeledBarrierGuardSig BaseGuard> {
51+
deprecated module MakeLabeledBarrierGuard<DeprecationWrapper::LabeledBarrierGuardSig BaseGuard> {
5052
final private class FinalBaseGuard = BaseGuard;
5153

5254
private class Adapter extends FinalBaseGuard {

javascript/ql/lib/semmle/javascript/dataflow/internal/FlowSteps.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -545,9 +545,9 @@ class Boolean extends boolean {
545545
/**
546546
* A summary of an inter-procedural data flow path.
547547
*/
548-
newtype TPathSummary =
548+
deprecated newtype TPathSummary =
549549
/** A summary of an inter-procedural data flow path. */
550-
MkPathSummary(Boolean hasReturn, Boolean hasCall, FlowLabel start, FlowLabel end)
550+
deprecated MkPathSummary(Boolean hasReturn, Boolean hasCall, FlowLabel start, FlowLabel end)
551551

552552
/**
553553
* A summary of an inter-procedural data flow path.
@@ -560,7 +560,7 @@ newtype TPathSummary =
560560
* We only want to build properly matched call/return sequences, so if a path has both
561561
* call steps and return steps, all return steps must precede all call steps.
562562
*/
563-
class PathSummary extends TPathSummary {
563+
deprecated class PathSummary extends TPathSummary {
564564
Boolean hasReturn;
565565
Boolean hasCall;
566566
FlowLabel start;
@@ -634,7 +634,7 @@ class PathSummary extends TPathSummary {
634634
}
635635
}
636636

637-
module PathSummary {
637+
deprecated module PathSummary {
638638
/**
639639
* Gets a summary describing a path without any calls or returns.
640640
*/
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* Contains a class with flow states that are used by multiple queries.
3+
*/
4+
5+
private import javascript
6+
private import TaintedUrlSuffixCustomizations
7+
private import TaintedObjectCustomizations
8+
9+
private newtype TFlowState =
10+
TTaint() or
11+
TTaintedUrlSuffix() or
12+
TTaintedPrefix() or
13+
TTaintedObject()
14+
15+
/**
16+
* A flow state indicating which part of a value is tainted.
17+
*/
18+
class FlowState extends TFlowState {
19+
/**
20+
* Holds if this represents a value that is considered entirely tainted, except the first character
21+
* might not be user-controlled.
22+
*/
23+
predicate isTaint() { this = TTaint() }
24+
25+
/**
26+
* Holds if this represents a URL whose fragment and/or query parts are considered tainted.
27+
*/
28+
predicate isTaintedUrlSuffix() { this = TTaintedUrlSuffix() }
29+
30+
/**
31+
* Holds if this represents a string whose prefix is known to be tainted.
32+
*/
33+
predicate isTaintedPrefix() { this = TTaintedPrefix() }
34+
35+
/**
36+
* Holds if this represents a deeply tainted object, such as a JSON object
37+
* parsed from user-controlled data.
38+
*/
39+
predicate isTaintedObject() { this = TTaintedObject() }
40+
41+
/** Gets a string representation of this flow state. */
42+
string toString() {
43+
this.isTaint() and result = "taint"
44+
or
45+
this.isTaintedUrlSuffix() and result = "tainted-url-suffix"
46+
or
47+
this.isTaintedPrefix() and result = "tainted-prefix"
48+
or
49+
this.isTaintedObject() and result = "tainted-object"
50+
}
51+
52+
/** DEPRECATED. Gets the corresponding flow label. */
53+
deprecated DataFlow::FlowLabel toFlowLabel() {
54+
this.isTaint() and result.isTaint()
55+
or
56+
this.isTaintedUrlSuffix() and result = TaintedUrlSuffix::label()
57+
or
58+
this.isTaintedPrefix() and result = "PrefixString"
59+
or
60+
this.isTaintedObject() and result = TaintedObject::label()
61+
}
62+
}
63+
64+
/** Convenience predicates for working with common flow states. */
65+
module FlowState {
66+
/**
67+
* Gets the flow state representing a value that is considered entirely tainted, except the first character
68+
* might not be user-controlled.
69+
*/
70+
FlowState taint() { result.isTaint() }
71+
72+
/**
73+
* Gets the flow state representing a URL whose fragment and/or query parts are considered tainted.
74+
*/
75+
FlowState taintedUrlSuffix() { result.isTaintedUrlSuffix() }
76+
77+
/**
78+
* Gets the flow state representing a string whose prefix is known to be tainted.
79+
*/
80+
FlowState taintedPrefix() { result.isTaintedPrefix() }
81+
82+
/**
83+
* Gets the flow state representing a deeply tainted object, such as a JSON object
84+
* parsed from user-controlled data.
85+
*/
86+
FlowState taintedObject() { result.isTaintedObject() }
87+
88+
/** DEPRECATED. Gets the flow state corresponding to `label`. */
89+
deprecated FlowState fromFlowLabel(DataFlow::FlowLabel label) { result.toFlowLabel() = label }
90+
}

0 commit comments

Comments
 (0)