Skip to content

Commit 2db89c1

Browse files
committed
JS: Update query17 from intro tutorial
1 parent 2722c45 commit 2db89c1

File tree

2 files changed

+26
-40
lines changed

2 files changed

+26
-40
lines changed

docs/codeql/codeql-language-guides/codeql-library-for-javascript.rst

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -700,55 +700,44 @@ The data flow graph-based analyses described so far are all intraprocedural: the
700700

701701
We distinguish here between data flow proper, and *taint tracking*: the latter not only considers value-preserving flow (such as from variable definitions to uses), but also cases where one value influences ("taints") another without determining it entirely. For example, in the assignment ``s2 = s1.substring(i)``, the value of ``s1`` influences the value of ``s2``, because ``s2`` is assigned a substring of ``s1``. In general, ``s2`` will not be assigned ``s1`` itself, so there is no data flow from ``s1`` to ``s2``, but ``s1`` still taints ``s2``.
702702

703-
It is a common pattern that we wish to specify data flow or taint analysis in terms of its *sources* (where flow starts), *sinks* (where it should be tracked), and *barriers* or *sanitizers* (where flow is interrupted). Sanitizers they are very common in security analyses: for example, an analysis that tracks the flow of untrusted user input into, say, a SQL query has to keep track of code that validates the input, thereby making it safe to use. Such a validation step is an example of a sanitizer.
703+
It is a common pattern that we wish to specify data flow or taint analysis in terms of its *sources* (where flow starts), *sinks* (where it should be tracked), and *barriers* (also called *sanitizers*) where flow is interrupted. Sanitizers they are very common in security analyses: for example, an analysis that tracks the flow of untrusted user input into, say, a SQL query has to keep track of code that validates the input, thereby making it safe to use. Such a validation step is an example of a sanitizer.
704704

705-
The classes ``DataFlow::Configuration`` and ``TaintTracking::Configuration`` allow specifying a data flow or taint analysis, respectively, by overriding the following predicates:
705+
A module implementing the signature `DataFlow::ConfigSig` may specify a data flow or taint analysis by implementing the following predicates:
706706

707707
- ``isSource(DataFlow::Node nd)`` selects all nodes ``nd`` from where flow tracking starts.
708708
- ``isSink(DataFlow::Node nd)`` selects all nodes ``nd`` to which the flow is tracked.
709-
- ``isBarrier(DataFlow::Node nd)`` selects all nodes ``nd`` that act as a barrier for data flow; ``isSanitizer`` is the corresponding predicate for taint tracking configurations.
710-
- ``isBarrierEdge(DataFlow::Node src, DataFlow::Node trg)`` is a variant of ``isBarrier(nd)`` that allows specifying barrier *edges* in addition to barrier nodes; again, ``isSanitizerEdge`` is the corresponding predicate for taint tracking;
709+
- ``isBarrier(DataFlow::Node nd)`` selects all nodes ``nd`` that act as a barrier/sanitizer for data flow.
711710
- ``isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg)`` allows specifying custom additional flow steps for this analysis; ``isAdditionalTaintStep`` is the corresponding predicate for taint tracking configurations.
712711

713-
Since for technical reasons both ``Configuration`` classes are subtypes of ``string``, you have to choose a unique name for each flow configuration and equate ``this`` with it in the characteristic predicate (as in the example below).
714-
715-
The predicate ``Configuration.hasFlow`` performs the actual flow tracking, starting at a source and looking for flow to a sink that does not pass through a barrier node or edge.
712+
Such a module can be passed to ``DataFlow::Global<...>``. This will produce a module with a ``flow`` predicate that performs the actual flow tracking, starting at a source and looking for flow to a sink that does not pass through a barrier node.
716713

717714
For example, suppose that we are developing an analysis to find hard-coded passwords. We might write a simple query that looks for string constants flowing into variables named ``"password"``.
718715

719716
.. code-block:: ql
720717
721718
import javascript
722719
723-
class PasswordTracker extends DataFlow::Configuration {
724-
PasswordTracker() {
725-
// unique identifier for this configuration
726-
this = "PasswordTracker"
727-
}
720+
module PasswordConfig implements DataFlow::ConfigSig {
721+
predicate isSource(DataFlow::Node nd) { nd.asExpr() instanceof StringLiteral }
728722
729-
override predicate isSource(DataFlow::Node nd) {
730-
nd.asExpr() instanceof StringLiteral
731-
}
732-
733-
override predicate isSink(DataFlow::Node nd) {
734-
passwordVarAssign(_, nd)
735-
}
723+
predicate isSink(DataFlow::Node nd) { passwordVarAssign(_, nd) }
724+
}
736725
737-
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
738-
v.getAnAssignedExpr() = nd.asExpr() and
739-
v.getName().toLowerCase() = "password"
740-
}
726+
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
727+
v.getAnAssignedExpr() = nd.asExpr() and
728+
v.getName().toLowerCase() = "password"
741729
}
742730
743-
Now we can rephrase our query to use ``Configuration.hasFlow``:
731+
module PasswordFlow = DataFlow::Global<PasswordConfig>;
732+
733+
Now we can rephrase our query to use ``PasswordFlow::flow``:
744734

745735
.. code-block:: ql
746736
747-
from PasswordTracker pt, DataFlow::Node source, DataFlow::Node sink, Variable v
748-
where pt.hasFlow(source, sink) and pt.passwordVarAssign(v, sink)
737+
from DataFlow::Node source, DataFlow::Node sink, Variable v
738+
where PasswordFlow::flow(_, sink) and passwordVarAssign(v, sink)
749739
select sink, "Password variable " + v + " is assigned a constant string."
750740
751-
752741
Syntax errors
753742
~~~~~~~~~~~~~
754743

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11
import javascript
22

3-
class PasswordTracker extends DataFlow::Configuration {
4-
PasswordTracker() {
5-
// unique identifier for this configuration
6-
this = "PasswordTracker"
7-
}
3+
module PasswordConfig implements DataFlow::ConfigSig {
4+
predicate isSource(DataFlow::Node nd) { nd.asExpr() instanceof StringLiteral }
85

9-
override predicate isSource(DataFlow::Node nd) { nd.asExpr() instanceof StringLiteral }
10-
11-
override predicate isSink(DataFlow::Node nd) { this.passwordVarAssign(_, nd) }
6+
predicate isSink(DataFlow::Node nd) { passwordVarAssign(_, nd) }
7+
}
128

13-
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
14-
v.getAnAssignedExpr() = nd.asExpr() and
15-
v.getName().toLowerCase() = "password"
16-
}
9+
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
10+
v.getAnAssignedExpr() = nd.asExpr() and
11+
v.getName().toLowerCase() = "password"
1712
}
1813

14+
module PasswordFlow = DataFlow::Global<PasswordConfig>;
15+
1916
query predicate test_query17(DataFlow::Node sink, string res) {
20-
exists(PasswordTracker pt, Variable v | pt.hasFlow(_, sink) and pt.passwordVarAssign(v, sink) |
17+
exists(Variable v | PasswordFlow::flow(_, sink) and passwordVarAssign(v, sink) |
2118
res = "Password variable " + v.toString() + " is assigned a constant string."
2219
)
2320
}

0 commit comments

Comments
 (0)