Skip to content

Commit e2b0ec5

Browse files
committed
JS: Handle multiple and/or operators in SanitizerFunction
1 parent e8e2f7b commit e2b0ec5

4 files changed

Lines changed: 64 additions & 2 deletions

File tree

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,26 @@ module TaintTracking {
846846
override predicate appliesTo(Configuration cfg) { any() }
847847
}
848848

849+
/**
850+
* Gets an operand of the given `&&` operator.
851+
*
852+
* We use this to construct the transitive closure over a relation
853+
* that does not include all of `BinaryExpr.getAnOperand`.
854+
*/
855+
private Expr getALogicalAndOperand(LogAndExpr e) {
856+
result = e.getAnOperand()
857+
}
858+
859+
/**
860+
* Gets an operand of the given `||` operator.
861+
*
862+
* We use this to construct the transitive closure over a relation
863+
* that does not include all of `BinaryExpr.getAnOperand`.
864+
*/
865+
private Expr getALogicalOrOperand(LogOrExpr e) {
866+
result = e.getAnOperand()
867+
}
868+
849869
/**
850870
* A function that returns the result of a sanitizer check.
851871
*/
@@ -860,10 +880,10 @@ module TaintTracking {
860880
returnExpr = sanitizer.asExpr()
861881
or
862882
// ad hoc support for conjunctions:
863-
returnExpr.(LogAndExpr).getAnOperand() = sanitizer.asExpr() and sanitizerOutcome = true
883+
getALogicalAndOperand+(returnExpr) = sanitizer.asExpr() and sanitizerOutcome = true
864884
or
865885
// ad hoc support for disjunctions:
866-
returnExpr.(LogOrExpr).getAnOperand() = sanitizer.asExpr() and sanitizerOutcome = false
886+
getALogicalOrOperand+(returnExpr) = sanitizer.asExpr() and sanitizerOutcome = false
867887
|
868888
exists(SsaExplicitDefinition ssa |
869889
ssa.getDef().getSource() = returnExpr and

javascript/ql/test/library-tests/TaintTracking/BasicTaintTracking.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ typeInferenceMismatch
6969
| promise.js:5:25:5:32 | source() | promise.js:5:8:5:33 | bluebir ... urce()) |
7070
| promise.js:10:24:10:31 | source() | promise.js:10:8:10:32 | Promise ... urce()) |
7171
| promise.js:12:20:12:27 | source() | promise.js:13:8:13:23 | resolver.promise |
72+
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:14:10:14:14 | taint |
73+
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:33:14:33:18 | taint |
7274
| sanitizer-guards.js:2:11:2:18 | source() | sanitizer-guards.js:4:8:4:8 | x |
7375
| sanitizer-guards.js:13:14:13:21 | source() | sanitizer-guards.js:15:10:15:15 | this.x |
7476
| sanitizer-guards.js:13:14:13:21 | source() | sanitizer-guards.js:21:14:21:19 | this.x |

javascript/ql/test/library-tests/TaintTracking/DataFlowTracking.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:30:14:30:20 | x.value |
4242
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:41:10:41:18 | id(taint) |
4343
| partialCalls.js:4:17:4:24 | source() | partialCalls.js:51:14:51:14 | x |
44+
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:14:10:14:14 | taint |
45+
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:17:14:17:18 | taint |
46+
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:21:14:21:18 | taint |
47+
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:25:14:25:18 | taint |
48+
| sanitizer-function.js:12:17:12:24 | source() | sanitizer-function.js:33:14:33:18 | taint |
4449
| sanitizer-guards.js:2:11:2:18 | source() | sanitizer-guards.js:4:8:4:8 | x |
4550
| sanitizer-guards.js:13:14:13:21 | source() | sanitizer-guards.js:15:10:15:15 | this.x |
4651
| sanitizer-guards.js:13:14:13:21 | source() | sanitizer-guards.js:21:14:21:19 | this.x |
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
function test() {
2+
function myCheck1(x) {
3+
return x === "a" && something() && somethingElse();
4+
}
5+
function myCheck2(x) {
6+
return something() && x === "a" && somethingElse();
7+
}
8+
function myCheck3(x) {
9+
return something() && somethingElse() && x === "a";
10+
}
11+
12+
let taint = source();
13+
14+
sink(taint); // NOT OK
15+
16+
if (myCheck1(taint)) {
17+
sink(taint); // OK
18+
}
19+
20+
if (myCheck2(taint)) {
21+
sink(taint); // OK
22+
}
23+
24+
if (myCheck3(taint)) {
25+
sink(taint); // OK
26+
}
27+
28+
function badCheck(x) {
29+
return something && x + isSafe(x) != null;
30+
}
31+
32+
if (badCheck(taint)) {
33+
sink(taint); // NOT OK
34+
}
35+
}

0 commit comments

Comments
 (0)