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

Skip to content

Commit ba9edb4

Browse files
committed
JS: Port UnsafeShellCommandConstruction
1 parent d08e450 commit ba9edb4

4 files changed

Lines changed: 280 additions & 673 deletions

File tree

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

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ module UnsafeShellCommandConstruction {
4646
*/
4747
abstract class Sanitizer extends DataFlow::Node { }
4848

49+
/**
50+
* A barrier guard for shell command constructed from library input vulnerabilities.
51+
*/
52+
abstract class BarrierGuard extends DataFlow::Node {
53+
/**
54+
* Holds if this node acts as a barrier for data flow, blocking further flow from `e` if `this` evaluates to `outcome`.
55+
*/
56+
predicate blocksExpr(boolean outcome, Expr e) { none() }
57+
}
58+
59+
/** A subclass of `BarrierGuard` that is used for backward compatibility with the old data flow library. */
60+
abstract class BarrierGuardLegacy extends BarrierGuard, TaintTracking::SanitizerGuardNode {
61+
override predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) }
62+
}
63+
4964
/**
5065
* A parameter of an exported function, seen as a source for shell command constructed from library input.
5166
*/
@@ -270,13 +285,13 @@ module UnsafeShellCommandConstruction {
270285
* A sanitizer that sanitizers paths that exist in the file-system.
271286
* For example: `x` is sanitized in `fs.existsSync(x)` or `fs.existsSync(x + "/suffix/path")`.
272287
*/
273-
class PathExistsSanitizerGuard extends TaintTracking::SanitizerGuardNode, DataFlow::CallNode {
288+
class PathExistsSanitizerGuard extends BarrierGuardLegacy, DataFlow::CallNode {
274289
PathExistsSanitizerGuard() {
275290
this = DataFlow::moduleMember("path", "exist").getACall() or
276291
this = DataFlow::moduleMember("fs", "existsSync").getACall()
277292
}
278293

279-
override predicate sanitizes(boolean outcome, Expr e) {
294+
override predicate blocksExpr(boolean outcome, Expr e) {
280295
outcome = true and
281296
(
282297
e = this.getArgument(0).asExpr() or
@@ -289,26 +304,26 @@ module UnsafeShellCommandConstruction {
289304
* A guard of the form `typeof x === "<T>"`, where `<T>` is "number", or "boolean",
290305
* which sanitizes `x` in its "then" branch.
291306
*/
292-
class TypeOfSanitizer extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode {
307+
class TypeOfSanitizer extends BarrierGuardLegacy, DataFlow::ValueNode {
293308
Expr x;
294309
override EqualityTest astNode;
295310

296311
TypeOfSanitizer() { TaintTracking::isTypeofGuard(astNode, x, ["number", "boolean"]) }
297312

298-
override predicate sanitizes(boolean outcome, Expr e) {
313+
override predicate blocksExpr(boolean outcome, Expr e) {
299314
outcome = astNode.getPolarity() and
300315
e = x
301316
}
302317
}
303318

304319
/** A guard that checks whether `x` is a number. */
305-
class NumberGuard extends TaintTracking::SanitizerGuardNode instanceof DataFlow::CallNode {
320+
class NumberGuard extends BarrierGuardLegacy instanceof DataFlow::CallNode {
306321
Expr x;
307322
boolean polarity;
308323

309324
NumberGuard() { TaintTracking::isNumberGuard(this, x, polarity) }
310325

311-
override predicate sanitizes(boolean outcome, Expr e) { e = x and outcome = polarity }
326+
override predicate blocksExpr(boolean outcome, Expr e) { e = x and outcome = polarity }
312327
}
313328

314329
private import semmle.javascript.dataflow.internal.AccessPaths

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,38 @@ import UnsafeShellCommandConstructionCustomizations::UnsafeShellCommandConstruct
1313
/**
1414
* A taint-tracking configuration for reasoning about shell command constructed from library input vulnerabilities.
1515
*/
16-
class Configuration extends TaintTracking::Configuration {
16+
module UnsafeShellCommandConstructionConfig implements DataFlow::ConfigSig {
17+
// TODO: we get a FP in the test case due to SanitizingRegExpTest not being able to generate a barrier edge
18+
// for an edge into a phi node.
19+
predicate isSource(DataFlow::Node source) { source instanceof Source }
20+
21+
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
22+
23+
predicate isBarrier(DataFlow::Node node) {
24+
node instanceof Sanitizer or
25+
node = DataFlow::MakeBarrierGuard<BarrierGuard>::getABarrierNode() or
26+
node = TaintTracking::AdHocWhitelistCheckSanitizer::getABarrierNode()
27+
}
28+
29+
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
30+
none()
31+
// TODO: localFieldStep is too expensive with dataflow2
32+
// DataFlow::localFieldStep(pred, succ)
33+
}
34+
35+
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
36+
}
37+
38+
/**
39+
* Taint-tracking for reasoning about shell command constructed from library input vulnerabilities.
40+
*/
41+
module UnsafeShellCommandConstructionFlow =
42+
TaintTracking::Global<UnsafeShellCommandConstructionConfig>;
43+
44+
/**
45+
* DEPRECATED. Use the `UnsafeShellCommandConstructionFlow` module instead.
46+
*/
47+
deprecated class Configuration extends TaintTracking::Configuration {
1748
Configuration() { this = "UnsafeShellCommandConstruction" }
1849

1950
override predicate isSource(DataFlow::Node source) { source instanceof Source }

javascript/ql/src/Security/CWE-078/UnsafeShellCommandConstruction.ql

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515

1616
import javascript
1717
import semmle.javascript.security.dataflow.UnsafeShellCommandConstructionQuery
18-
import DataFlow::PathGraph
18+
import UnsafeShellCommandConstructionFlow::PathGraph
1919

20-
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Sink sinkNode
21-
where cfg.hasFlowPath(source, sink) and sinkNode = sink.getNode()
20+
from
21+
UnsafeShellCommandConstructionFlow::PathNode source,
22+
UnsafeShellCommandConstructionFlow::PathNode sink, Sink sinkNode
23+
where UnsafeShellCommandConstructionFlow::flowPath(source, sink) and sinkNode = sink.getNode()
2224
select sinkNode.getAlertLocation(), source, sink,
2325
"This " + sinkNode.getSinkType() + " which depends on $@ is later used in a $@.",
2426
source.getNode(), "library input", sinkNode.getCommandExecution(), "shell command"

0 commit comments

Comments
 (0)