Skip to content

Commit 042c0b0

Browse files
Covered sandboxes for JEXL 2
- Updated SandboxedJexlFlowConfig to cover JEXL 2 - Added SandboxedJexl2 test
1 parent 7543df6 commit 042c0b0

File tree

6 files changed

+107
-8
lines changed

6 files changed

+107
-8
lines changed

java/ql/src/experimental/Security/CWE/CWE-094/JexlInjectionLib.qll

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,7 @@ private predicate isUnsafeEngine(Expr expr) {
109109
private class SandboxedJexlFlowConfig extends DataFlow2::Configuration {
110110
SandboxedJexlFlowConfig() { this = "JexlInjection::SandboxedJexlFlowConfig" }
111111

112-
override predicate isSource(DataFlow::Node node) {
113-
exists(MethodAccess ma, Method m | m = ma.getMethod() |
114-
m.getDeclaringType() instanceof JexlBuilder and
115-
m.hasName(["uberspect", "sandbox"]) and
116-
m.getReturnType() instanceof JexlBuilder and
117-
(ma = node.asExpr() or ma.getQualifier() = node.asExpr())
118-
)
119-
}
112+
override predicate isSource(DataFlow::Node node) { node instanceof SandboxedJexlSource }
120113

121114
override predicate isSink(DataFlow::Node node) {
122115
node.asExpr().getType() instanceof JexlEngine or
@@ -129,6 +122,26 @@ private class SandboxedJexlFlowConfig extends DataFlow2::Configuration {
129122
}
130123
}
131124

125+
/**
126+
* Defines a data flow source for Jexl engines configured with a sandbox.
127+
*/
128+
private class SandboxedJexlSource extends DataFlow::ExprNode {
129+
SandboxedJexlSource() {
130+
exists(MethodAccess ma, Method m | m = ma.getMethod() |
131+
m.getDeclaringType() instanceof JexlBuilder and
132+
m.hasName(["uberspect", "sandbox"]) and
133+
m.getReturnType() instanceof JexlBuilder and
134+
(ma = this.asExpr() or ma.getQualifier() = this.asExpr())
135+
)
136+
or
137+
exists(ConstructorCall cc |
138+
cc.getConstructedType() instanceof JexlEngine and
139+
cc.getArgument(0).getType() instanceof JexlUberspect and
140+
cc = this.asExpr()
141+
)
142+
}
143+
}
144+
132145
/**
133146
* Holds if `fromNode` to `toNode` is a dataflow step that creates one of the Jexl engines.
134147
*/
@@ -139,6 +152,12 @@ private predicate createsJexlEngine(DataFlow::Node fromNode, DataFlow::Node toNo
139152
ma.getQualifier() = fromNode.asExpr() and
140153
ma = toNode.asExpr()
141154
)
155+
or
156+
exists(ConstructorCall cc |
157+
cc.getConstructedType() instanceof UnifiedJexl and
158+
cc.getArgument(0) = fromNode.asExpr() and
159+
cc = toNode.asExpr()
160+
)
142161
}
143162

144163
/**
@@ -249,6 +268,13 @@ private class UnifiedJexl extends JexlRefType {
249268
UnifiedJexl() { hasName("UnifiedJEXL") }
250269
}
251270

271+
private class JexlUberspect extends Interface {
272+
JexlUberspect() {
273+
hasQualifiedName("org.apache.commons.jexl2.introspection", "Uberspect") or
274+
hasQualifiedName("org.apache.commons.jexl3.introspection", "JexlUberspect")
275+
}
276+
}
277+
252278
private class JxltEngineExpression extends NestedType {
253279
JxltEngineExpression() { getEnclosingType() instanceof JxltEngine and hasName("Expression") }
254280
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import org.apache.commons.jexl2.*;
2+
import org.apache.commons.jexl2.introspection.*;
3+
4+
import java.net.ServerSocket;
5+
import java.net.Socket;
6+
import java.util.function.Consumer;
7+
8+
public class SandboxedJexl2 {
9+
10+
private static void runJexlExpressionWithSandbox(String jexlExpr) {
11+
Sandbox sandbox = new Sandbox();
12+
sandbox.white(SandboxedJexl2.class.getCanonicalName());
13+
Uberspect uberspect = new SandboxUberspectImpl(null, sandbox);
14+
JexlEngine jexl = new JexlEngine(uberspect, null, null, null);
15+
Expression e = jexl.createExpression(jexlExpr);
16+
JexlContext jc = new MapContext();
17+
e.evaluate(jc);
18+
}
19+
20+
private static void runJexlExpressionViaSandboxedUnifiedJexl(String jexlExpr) {
21+
Sandbox sandbox = new Sandbox();
22+
sandbox.white(SandboxedJexl2.class.getCanonicalName());
23+
Uberspect uberspect = new SandboxUberspectImpl(null, sandbox);
24+
JexlEngine jexl = new JexlEngine(uberspect, null, null, null);
25+
UnifiedJEXL unifiedJEXL = new UnifiedJEXL(jexl);
26+
unifiedJEXL.parse(jexlExpr).evaluate(new MapContext());
27+
}
28+
29+
private static void simpleServer(Consumer<String> action) throws Exception {
30+
try (ServerSocket serverSocket = new ServerSocket(0)) {
31+
try (Socket socket = serverSocket.accept()) {
32+
byte[] bytes = new byte[1024];
33+
int n = socket.getInputStream().read(bytes);
34+
String jexlExpr = new String(bytes, 0, n);
35+
action.accept(jexlExpr);
36+
}
37+
}
38+
}
39+
40+
public static void saferJexlExpressionEvaluate() throws Exception {
41+
simpleServer(SandboxedJexl2::runJexlExpressionWithSandbox);
42+
}
43+
44+
public static void saferJexlExpressionEvaluateViaUnifiedJexl() throws Exception {
45+
simpleServer(SandboxedJexl2::runJexlExpressionViaSandboxedUnifiedJexl);
46+
}
47+
}

java/ql/test/stubs/apache-commons-jexl-2.1.1/org/apache/commons/jexl2/JexlEngine.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package org.apache.commons.jexl2;
22

3+
import java.util.Map;
4+
import org.apache.commons.jexl2.introspection.*;
5+
36
public class JexlEngine {
47

8+
public JexlEngine() {}
9+
10+
public JexlEngine(Uberspect uberspect, Object arithmetic, Map<String, Object> functions, Object log) {}
11+
512
public Expression createExpression(String expression) {
613
return null;
714
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.apache.commons.jexl2.introspection;
2+
3+
public class Sandbox {
4+
5+
public Permissions white(String clazz) {
6+
return null;
7+
}
8+
9+
public static class Permissions {}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package org.apache.commons.jexl2.introspection;
2+
3+
public class SandboxUberspectImpl implements Uberspect {
4+
5+
public SandboxUberspectImpl(Object log, Sandbox sandbox) {}
6+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package org.apache.commons.jexl2.introspection;
2+
3+
public interface Uberspect {}

0 commit comments

Comments
 (0)