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

Skip to content

Commit 65e9706

Browse files
committed
JS: Port TaintedPath
1 parent fcfab52 commit 65e9706

8 files changed

Lines changed: 667 additions & 9941 deletions

File tree

javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathCustomizations.qll

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,28 @@ module TaintedPath {
3131
/**
3232
* A barrier guard for tainted-path vulnerabilities.
3333
*/
34-
abstract class BarrierGuardNode extends DataFlow::LabeledBarrierGuardNode { }
34+
abstract class BarrierGuard extends DataFlow::Node {
35+
/**
36+
* Holds if this node acts as a barrier for data flow, blocking further flow from `e` if `this` evaluates to `outcome`.
37+
*/
38+
predicate blocksExpr(boolean outcome, Expr e) { none() }
39+
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) { none() }
44+
}
45+
46+
/** A subclass of `BarrierGuard` that is used for backward compatibility with the old data flow library. */
47+
abstract class BarrierGuardLegacy extends BarrierGuard, TaintTracking::SanitizerGuardNode {
48+
override predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) }
49+
50+
override predicate sanitizes(boolean outcome, Expr e, DataFlow::FlowLabel label) {
51+
this.blocksExpr(outcome, e, label)
52+
}
53+
}
54+
55+
deprecated class BarrierGuardNode = BarrierGuard;
3556

3657
module Label {
3758
/**
@@ -345,10 +366,10 @@ module TaintedPath {
345366
*
346367
* This is relevant for paths that are known to be normalized.
347368
*/
348-
class StartsWithDotDotSanitizer extends BarrierGuardNode instanceof StringOps::StartsWith {
369+
class StartsWithDotDotSanitizer extends BarrierGuard instanceof StringOps::StartsWith {
349370
StartsWithDotDotSanitizer() { isDotDotSlashPrefix(super.getSubstring()) }
350371

351-
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
372+
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
352373
// Sanitize in the false case for:
353374
// .startsWith(".")
354375
// .startsWith("..")
@@ -365,12 +386,12 @@ module TaintedPath {
365386
/**
366387
* A check of the form `whitelist.includes(x)` or equivalent, which sanitizes `x` in its "then" branch.
367388
*/
368-
class MembershipTestBarrierGuard extends BarrierGuardNode {
389+
class MembershipTestBarrierGuard extends BarrierGuard {
369390
MembershipCandidate candidate;
370391

371392
MembershipTestBarrierGuard() { this = candidate.getTest() }
372393

373-
override predicate blocks(boolean outcome, Expr e) {
394+
override predicate blocksExpr(boolean outcome, Expr e) {
374395
candidate = e.flow() and
375396
candidate.getTestPolarity() = outcome
376397
}
@@ -380,7 +401,7 @@ module TaintedPath {
380401
* A check of form `x.startsWith(dir)` that sanitizes normalized absolute paths, since it is then
381402
* known to be in a subdirectory of `dir`.
382403
*/
383-
class StartsWithDirSanitizer extends BarrierGuardNode {
404+
class StartsWithDirSanitizer extends BarrierGuard {
384405
StringOps::StartsWith startsWith;
385406

386407
StartsWithDirSanitizer() {
@@ -390,7 +411,7 @@ module TaintedPath {
390411
not startsWith.getSubstring().getStringValue() = "/"
391412
}
392413

393-
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
414+
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
394415
outcome = startsWith.getPolarity() and
395416
e = startsWith.getBaseString().asExpr() and
396417
exists(Label::PosixPath posixPath | posixPath = label |
@@ -404,7 +425,7 @@ module TaintedPath {
404425
* A call to `path.isAbsolute` as a sanitizer for relative paths in true branch,
405426
* and a sanitizer for absolute paths in the false branch.
406427
*/
407-
class IsAbsoluteSanitizer extends BarrierGuardNode {
428+
class IsAbsoluteSanitizer extends BarrierGuard {
408429
DataFlow::Node operand;
409430
boolean polarity;
410431
boolean negatable;
@@ -425,7 +446,7 @@ module TaintedPath {
425446
) // !x.startsWith("/home") does not guarantee that x is not absolute
426447
}
427448

428-
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
449+
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
429450
e = operand.asExpr() and
430451
exists(Label::PosixPath posixPath | posixPath = label |
431452
outcome = polarity and posixPath.isRelative()
@@ -440,10 +461,10 @@ module TaintedPath {
440461
/**
441462
* An expression of form `x.includes("..")` or similar.
442463
*/
443-
class ContainsDotDotSanitizer extends BarrierGuardNode instanceof StringOps::Includes {
464+
class ContainsDotDotSanitizer extends BarrierGuard instanceof StringOps::Includes {
444465
ContainsDotDotSanitizer() { isDotDotSlashPrefix(super.getSubstring()) }
445466

446-
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
467+
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
447468
e = super.getBaseString().asExpr() and
448469
outcome = super.getPolarity().booleanNot() and
449470
label.(Label::PosixPath).canContainDotDotSlash() // can still be bypassed by normalized absolute path
@@ -453,10 +474,10 @@ module TaintedPath {
453474
/**
454475
* An expression of form `x.matches(/\.\./)` or similar.
455476
*/
456-
class ContainsDotDotRegExpSanitizer extends BarrierGuardNode instanceof StringOps::RegExpTest {
477+
class ContainsDotDotRegExpSanitizer extends BarrierGuard instanceof StringOps::RegExpTest {
457478
ContainsDotDotRegExpSanitizer() { super.getRegExp().getAMatchedString() = [".", "..", "../"] }
458479

459-
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
480+
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
460481
e = super.getStringOperand().asExpr() and
461482
outcome = super.getPolarity().booleanNot() and
462483
label.(Label::PosixPath).canContainDotDotSlash() // can still be bypassed by normalized absolute path
@@ -484,7 +505,7 @@ module TaintedPath {
484505
* }
485506
* ```
486507
*/
487-
class RelativePathStartsWithSanitizer extends BarrierGuardNode {
508+
class RelativePathStartsWithSanitizer extends BarrierGuard {
488509
StringOps::StartsWith startsWith;
489510
DataFlow::CallNode pathCall;
490511
string member;
@@ -506,7 +527,7 @@ module TaintedPath {
506527
(not member = "relative" or isDotDotSlashPrefix(startsWith.getSubstring()))
507528
}
508529

509-
override predicate blocks(boolean outcome, Expr e) {
530+
override predicate blocksExpr(boolean outcome, Expr e) {
510531
member = "relative" and
511532
e = this.maybeGetPathSuffix(pathCall.getArgument(1)).asExpr() and
512533
outcome = startsWith.getPolarity().booleanNot()
@@ -542,7 +563,7 @@ module TaintedPath {
542563
* An expression of form `isInside(x, y)` or similar, where `isInside` is
543564
* a library check for the relation between `x` and `y`.
544565
*/
545-
class IsInsideCheckSanitizer extends BarrierGuardNode {
566+
class IsInsideCheckSanitizer extends BarrierGuard {
546567
DataFlow::Node checked;
547568
boolean onlyNormalizedAbsolutePaths;
548569

@@ -558,7 +579,7 @@ module TaintedPath {
558579
)
559580
}
560581

561-
override predicate blocks(boolean outcome, Expr e, DataFlow::FlowLabel label) {
582+
override predicate blocksExpr(boolean outcome, Expr e, DataFlow::FlowLabel label) {
562583
(
563584
onlyNormalizedAbsolutePaths = true and
564585
label.(Label::PosixPath).isNormalized() and
@@ -750,8 +771,6 @@ module TaintedPath {
750771
)
751772
)
752773
or
753-
TaintTracking::promiseStep(src, dst) and srclabel = dstlabel
754-
or
755774
TaintTracking::persistentStorageStep(src, dst) and srclabel = dstlabel
756775
or
757776
exists(DataFlow::PropRead read | read = dst |

javascript/ql/lib/semmle/javascript/security/dataflow/TaintedPathQuery.qll

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
import javascript
11-
import TaintedPathCustomizations::TaintedPath
11+
private import TaintedPathCustomizations::TaintedPath
1212

1313
// Materialize flow labels
1414
private class ConcretePosixPath extends Label::PosixPath {
@@ -22,7 +22,44 @@ private class ConcreteSplitPath extends Label::SplitPath {
2222
/**
2323
* A taint-tracking configuration for reasoning about tainted-path vulnerabilities.
2424
*/
25-
class Configuration extends DataFlow::Configuration {
25+
module TaintedPathConfig implements DataFlow::StateConfigSig {
26+
class FlowState = DataFlow::FlowLabel;
27+
28+
predicate isSource(DataFlow::Node source, DataFlow::FlowLabel state) {
29+
state = source.(Source).getAFlowLabel()
30+
}
31+
32+
predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel state) {
33+
state = sink.(Sink).getAFlowLabel()
34+
}
35+
36+
predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel label) {
37+
node instanceof Sanitizer and exists(label)
38+
or
39+
node = DataFlow::MakeLabeledBarrierGuard<BarrierGuard>::getABarrierNode(label)
40+
}
41+
42+
predicate isBarrier(DataFlow::Node node) {
43+
node = DataFlow::MakeBarrierGuard<BarrierGuard>::getABarrierNode()
44+
}
45+
46+
predicate isAdditionalFlowStep(
47+
DataFlow::Node node1, DataFlow::FlowLabel state1, DataFlow::Node node2,
48+
DataFlow::FlowLabel state2
49+
) {
50+
isAdditionalTaintedPathFlowStep(node1, node2, state1, state2)
51+
}
52+
}
53+
54+
/**
55+
* Taint-tracking for reasoning about tainted-path vulnerabilities.
56+
*/
57+
module TaintedPathFlow = DataFlow::GlobalWithState<TaintedPathConfig>;
58+
59+
/**
60+
* DEPRECATED. Use the `TaintedPathFlow` module instead.
61+
*/
62+
deprecated class Configuration extends DataFlow::Configuration {
2663
Configuration() { this = "TaintedPath" }
2764

2865
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {

javascript/ql/src/Security/CWE-022/TaintedPath.ql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717

1818
import javascript
1919
import semmle.javascript.security.dataflow.TaintedPathQuery
20-
import DataFlow::PathGraph
20+
import DataFlow::DeduplicatePathGraph<TaintedPathFlow::PathNode, TaintedPathFlow::PathGraph>
2121

22-
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
23-
where cfg.hasFlowPath(source, sink)
22+
from PathNode source, PathNode sink
23+
where TaintedPathFlow::flowPath(source.getAnOriginalPathNode(), sink.getAnOriginalPathNode())
2424
select sink.getNode(), source, sink, "This path depends on a $@.", source.getNode(),
2525
"user-provided value"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
import javascript
22
import semmle.javascript.security.dataflow.TaintedPathQuery
33
import testUtilities.ConsistencyChecking
4+
5+
class TaintedPathConsistency extends ConsistencyConfiguration {
6+
TaintedPathConsistency() { this = "TaintedPathConsistency" }
7+
8+
override DataFlow::Node getAnAlert() { TaintedPathFlow::flowTo(result) }
9+
}

0 commit comments

Comments
 (0)