Skip to content

Commit b3e88cd

Browse files
committed
refactored multiple implementations of getEnclosingTryStmt into a single predicate
1 parent 1b81526 commit b3e88cd

File tree

3 files changed

+47
-49
lines changed

3 files changed

+47
-49
lines changed

javascript/ql/src/semmle/javascript/Stmt.qll

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ class Stmt extends @stmt, ExprOrStmt, Documentable {
5555
}
5656

5757
override predicate isAmbient() { hasDeclareKeyword(this) or getParent().isAmbient() }
58+
59+
/**
60+
* Gets the `try` statement containing this statement without crossing function
61+
* boundaries or other `try ` statements.
62+
*/
63+
TryStmt getEnclosingTryStmt() {
64+
getParentStmt+() = result.getBody() and
65+
not exists(TryStmt mid |
66+
getParentStmt+() = mid.getBody() and mid.getParentStmt+() = result.getBody()
67+
)
68+
}
5869
}
5970

6071
/**

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

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ predicate localExceptionStep(DataFlow::Node pred, DataFlow::Node succ) {
6767
DataFlow::exceptionalInvocationReturnNode(pred, expr)
6868
|
6969
// Propagate out of enclosing function.
70-
not exists(getEnclosingTryStmt(expr.getEnclosingStmt())) and
70+
not exists(expr.getEnclosingStmt().getEnclosingTryStmt()) and
7171
exists(Function f |
7272
f = expr.getEnclosingFunction() and
7373
DataFlow::exceptionalFunctionReturnNode(succ, f)
@@ -76,7 +76,7 @@ predicate localExceptionStep(DataFlow::Node pred, DataFlow::Node succ) {
7676
// Propagate to enclosing try/catch.
7777
// To avoid false flow, we only propagate to an unguarded catch clause.
7878
exists(TryStmt try |
79-
try = getEnclosingTryStmt(expr.getEnclosingStmt()) and
79+
try = expr.getEnclosingStmt().getEnclosingTryStmt() and
8080
DataFlow::parameterNode(succ, try.getCatchClause().getAParameter())
8181
)
8282
)
@@ -156,19 +156,6 @@ private module CachedSteps {
156156
cached
157157
predicate callStep(DataFlow::Node pred, DataFlow::Node succ) { argumentPassing(_, pred, _, succ) }
158158

159-
/**
160-
* Gets the `try` statement containing `stmt` without crossing function boundaries
161-
* or other `try ` statements.
162-
*/
163-
cached
164-
TryStmt getEnclosingTryStmt(Stmt stmt) {
165-
result.getBody() = stmt
166-
or
167-
not stmt instanceof Function and
168-
not stmt = any(TryStmt try).getBody() and
169-
result = getEnclosingTryStmt(stmt.getParentStmt())
170-
}
171-
172159
/**
173160
* Holds if there is a flow step from `pred` to `succ` through:
174161
* - returning a value from a function call, or
Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,36 @@
11
/**
2-
* Provides a taint-tracking configuration for reasoning about cross-site
3-
* scripting vulnerabilities where the taint-flow passes through a thrown
4-
* exception.
2+
* Provides a taint-tracking configuration for reasoning about cross-site
3+
* scripting vulnerabilities where the taint-flow passes through a thrown
4+
* exception.
55
*/
66

77
import javascript
88

99
module ExceptionXss {
1010
import DomBasedXssCustomizations::DomBasedXss as DomBasedXssCustom
11-
import ReflectedXssCustomizations::ReflectedXss as ReflectedXssCustom
12-
import Xss::DomBasedXss as DomBasedXss
11+
import ReflectedXssCustomizations::ReflectedXss as ReflectedXssCustom
12+
import Xss::DomBasedXss as DomBasedXss
1313
import Xss::ReflectedXss as ReflectedXSS
1414
import Xss::StoredXss as StoredXss
1515
import Xss as XSS
1616

1717
DataFlow::ExceptionalInvocationReturnNode getCallerExceptionalReturn(Function func) {
1818
exists(DataFlow::InvokeNode call |
1919
not call.isImprecise() and
20-
func = call.getACallee() and
20+
func = call.getACallee(0) and
2121
result = call.getExceptionalReturn()
2222
)
2323
}
2424

2525
DataFlow::Node getExceptionalSuccessor(DataFlow::Node pred) {
26-
if exists(getEnclosingTryStmt(pred.asExpr().getEnclosingStmt()))
26+
if exists(pred.asExpr().getEnclosingStmt().getEnclosingTryStmt())
2727
then
28-
result = DataFlow::parameterNode(getEnclosingTryStmt(pred
28+
result = DataFlow::parameterNode(pred
2929
.asExpr()
30-
.getEnclosingStmt()).getACatchClause().getAParameter())
30+
.getEnclosingStmt()
31+
.getEnclosingTryStmt()
32+
.getACatchClause()
33+
.getAParameter())
3134
else result = getCallerExceptionalReturn(pred.getContainer())
3235
}
3336

@@ -38,54 +41,51 @@ module ExceptionXss {
3841
node.asExpr().getEnclosingStmt() instanceof ThrowStmt
3942
}
4043

41-
TryStmt getEnclosingTryStmt(Stmt stmt) {
42-
stmt.getParentStmt+() = result.getBody() and
43-
not exists(TryStmt mid |
44-
stmt.getParentStmt+() = mid.getBody() and mid.getParentStmt+() = result.getBody()
45-
)
46-
}
47-
4844
/**
49-
* A FlowLabel representing tainted data that has not been thrown in an exception.
45+
* A FlowLabel representing tainted data that has not been thrown in an exception.
5046
* In the js/xss-through-exception query data-flow can only reach a sink after
51-
* the data has been thrown as an exception, and data that has not been thrown
52-
* as an exception therefore has this flow label, and only this flow label, associated with it.
47+
* the data has been thrown as an exception, and data that has not been thrown
48+
* as an exception therefore has this flow label, and only this flow label, associated with it.
5349
*/
5450
class NotYetThrown extends DataFlow::FlowLabel {
5551
NotYetThrown() { this = "NotYetThrown" }
5652
}
5753

5854
/**
59-
* A taint-tracking configuration for reasoning about XSS with possible exceptional flow.
60-
* Flow labels are used to ensure that we only report taint-flow that has been thrown in
61-
* an exception.
55+
* A taint-tracking configuration for reasoning about XSS with possible exceptional flow.
56+
* Flow labels are used to ensure that we only report taint-flow that has been thrown in
57+
* an exception.
6258
*/
6359
class Configuration extends TaintTracking::Configuration {
64-
Configuration() { this = "ExceptionXss"}
60+
Configuration() { this = "ExceptionXss" }
6561

6662
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
6763
source instanceof XSS::Shared::Source and label instanceof NotYetThrown
6864
}
69-
65+
7066
override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) {
7167
sink instanceof XSS::Shared::Sink and not label instanceof NotYetThrown
7268
}
7369

74-
override predicate isSanitizer(DataFlow::Node node) {
75-
node instanceof XSS::Shared::Sanitizer
76-
}
70+
override predicate isSanitizer(DataFlow::Node node) { node instanceof XSS::Shared::Sanitizer }
7771

78-
override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl) {
79-
inlbl instanceof NotYetThrown and (outlbl.isTaint() or outlbl instanceof NotYetThrown) and
72+
override predicate isAdditionalFlowStep(
73+
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel inlbl,
74+
DataFlow::FlowLabel outlbl
75+
) {
76+
inlbl instanceof NotYetThrown and
77+
(outlbl.isTaint() or outlbl instanceof NotYetThrown) and
8078
succ = getExceptionalSuccessor(pred) and
81-
(canThrowSensitiveInformation(pred) or pred = any(DataFlow::InvokeNode c).getExceptionalReturn())
79+
(
80+
canThrowSensitiveInformation(pred) or
81+
pred = any(DataFlow::InvokeNode c).getExceptionalReturn()
82+
)
8283
or
8384
// All the usual taint-flow steps apply on data-flow before it has been thrown in an exception.
84-
this.isAdditionalFlowStep(pred, succ) and inlbl instanceof NotYetThrown and outlbl instanceof NotYetThrown
85+
this.isAdditionalFlowStep(pred, succ) and inlbl instanceof NotYetThrown and outlbl instanceof NotYetThrown
8586
or
86-
// We taint an object deep if it happens before an exception has been thrown.
87-
inlbl instanceof NotYetThrown and outlbl instanceof NotYetThrown and
88-
exists(DataFlow::PropWrite write | write.getRhs() = pred and write.getBase() = succ)
87+
// We taint an object deep if it happens before an exception has been thrown.
88+
inlbl instanceof NotYetThrown and outlbl instanceof NotYetThrown and exists(DataFlow::PropWrite write | write.getRhs() = pred and write.getBase() = succ)
8989
}
9090
}
9191
}

0 commit comments

Comments
 (0)