Skip to content

Commit 0e75a1a

Browse files
committed
feat(java): Update to Java CmdExec queries
1 parent 711a715 commit 0e75a1a

File tree

8 files changed

+164
-135
lines changed

8 files changed

+164
-135
lines changed

java/lib/codeql-pack.lock.yml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,27 @@
22
lockVersion: 1.0.0
33
dependencies:
44
codeql/dataflow:
5-
version: 0.0.3
5+
version: 1.0.0
66
codeql/java-all:
7-
version: 0.7.4
7+
version: 1.0.0
88
codeql/mad:
9-
version: 0.1.4
9+
version: 1.0.0
10+
codeql/rangeanalysis:
11+
version: 1.0.0
1012
codeql/regex:
11-
version: 0.1.4
13+
version: 1.0.0
1214
codeql/ssa:
13-
version: 0.1.4
15+
version: 1.0.0
16+
codeql/threat-models:
17+
version: 1.0.0
1418
codeql/tutorial:
15-
version: 0.1.4
19+
version: 1.0.0
20+
codeql/typeflow:
21+
version: 1.0.0
1622
codeql/typetracking:
17-
version: 0.1.4
23+
version: 1.0.0
1824
codeql/util:
19-
version: 0.1.4
25+
version: 1.0.0
26+
codeql/xml:
27+
version: 1.0.0
2028
compiled: false

java/lib/ghsl/CommandInjectionRuntimeExec.qll

Lines changed: 75 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,124 +4,111 @@ import semmle.code.java.dataflow.DataFlow
44
private import semmle.code.java.dataflow.TaintTracking
55
import semmle.code.java.dataflow.FlowSources
66

7+
abstract class Source extends DataFlow::Node {
8+
Source() { this = this }
9+
}
710

8-
// a static string of an unsafe executable tainting arg 0 of Runtime.exec()
9-
class ExecTaintConfiguration extends TaintTracking::Configuration {
10-
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
11-
12-
override
13-
predicate
14-
isSource(DataFlow::Node source) {
15-
source.asExpr() instanceof StringLiteral
16-
and source.asExpr().(StringLiteral).getValue() instanceof UnSafeExecutable
11+
module RuntimeExec {
12+
// a static string of an unsafe executable tainting arg 0 of Runtime.exec()
13+
module RuntimeExecConfiguration implements DataFlow::ConfigSig {
14+
predicate isSource(DataFlow::Node source) {
15+
source.asExpr() instanceof StringLiteral and
16+
source.asExpr().(StringLiteral).getValue() instanceof UnSafeExecutable
1717
}
1818

19-
override
20-
predicate
21-
isSink(DataFlow::Node sink) {
22-
exists(RuntimeExecMethod method, MethodAccess call |
23-
call.getMethod() = method
24-
and sink.asExpr() = call.getArgument(0)
25-
and sink.asExpr().getType() instanceof Array
26-
)
19+
predicate isSink(DataFlow::Node sink) {
20+
exists(RuntimeExecMethod method, MethodCall call |
21+
call.getMethod() = method and
22+
sink.asExpr() = call.getArgument(0) and
23+
sink.asExpr().getType() instanceof Array
24+
)
2725
}
2826

29-
override
30-
predicate
31-
isSanitizer(DataFlow::Node node) {
32-
node.asExpr().getFile().isSourceFile() and
33-
(
34-
node instanceof AssignToNonZeroIndex
35-
or node instanceof ArrayInitAtNonZeroIndex
36-
or node instanceof StreamConcatAtNonZeroIndex
37-
or node.getType() instanceof PrimitiveType
38-
or node.getType() instanceof BoxedType
39-
)
27+
predicate isBarrier(DataFlow::Node node) {
28+
node.asExpr().getFile().isSourceFile() and
29+
(
30+
node instanceof AssignToNonZeroIndex or
31+
node instanceof ArrayInitAtNonZeroIndex or
32+
node instanceof StreamConcatAtNonZeroIndex or
33+
node.getType() instanceof PrimitiveType or
34+
node.getType() instanceof BoxedType
35+
)
4036
}
41-
}
37+
}
4238

43-
abstract class Source extends DataFlow::Node {
44-
Source() {
45-
this = this
46-
}
47-
}
39+
module RuntimeExecFlow = TaintTracking::Global<RuntimeExecConfiguration>;
4840

41+
import RuntimeExecFlow::PathGraph
42+
}
4943

5044
// taint flow from user data to args of the command
51-
class ExecTaintConfiguration2 extends TaintTracking::Configuration {
52-
ExecTaintConfiguration2() { this = "ExecTaintConfiguration2" }
53-
54-
override
55-
predicate
56-
isSource(DataFlow::Node source) {
57-
source instanceof Source
45+
module ExecTaint {
46+
module ExecTaintConfiguration implements DataFlow::ConfigSig {
47+
predicate isSource(DataFlow::Node source) { source instanceof Source }
48+
49+
predicate isSink(DataFlow::Node sink) {
50+
exists(RuntimeExecMethod method, MethodCall call, int index |
51+
call.getMethod() = method and
52+
sink.asExpr() = call.getArgument(index) and
53+
sink.asExpr().getType() instanceof Array
54+
)
5855
}
5956

60-
override
61-
predicate
62-
isSink(DataFlow::Node sink) {
63-
exists(RuntimeExecMethod method, MethodAccess call, int index |
64-
call.getMethod() = method
65-
and sink.asExpr() = call.getArgument(index)
66-
and sink.asExpr().getType() instanceof Array
67-
)
57+
predicate isBarrier(DataFlow::Node node) {
58+
node.asExpr().getFile().isSourceFile() and
59+
(
60+
node.getType() instanceof PrimitiveType or
61+
node.getType() instanceof BoxedType
62+
)
6863
}
64+
}
6965

70-
override
71-
predicate
72-
isSanitizer(DataFlow::Node node) {
73-
node.asExpr().getFile().isSourceFile() and
74-
(
75-
node.getType() instanceof PrimitiveType
76-
or node.getType() instanceof BoxedType
77-
)
78-
}
79-
}
66+
module ExecTaintFlow = TaintTracking::Global<ExecTaintConfiguration>;
8067

68+
import ExecTaintFlow::PathGraph
69+
}
8170

8271
// array[3] = node
8372
class AssignToNonZeroIndex extends DataFlow::Node {
84-
AssignExpr assign;
85-
ArrayAccess access;
86-
87-
AssignToNonZeroIndex() {
88-
assign.getDest() = access
89-
and access.getIndexExpr().(IntegerLiteral).getValue() != "0"
90-
and assign.getSource() = this.asExpr()
91-
}
73+
AssignExpr assign;
74+
ArrayAccess access;
75+
76+
AssignToNonZeroIndex() {
77+
assign.getDest() = access and
78+
access.getIndexExpr().(IntegerLiteral).getValue() != "0" and
79+
assign.getSource() = this.asExpr()
80+
}
9281
}
9382

94-
9583
// String[] array = {"a", "b, "c"};
9684
class ArrayInitAtNonZeroIndex extends DataFlow::Node {
97-
ArrayInit init;
98-
int index;
85+
ArrayInit init;
86+
int index;
9987

100-
ArrayInitAtNonZeroIndex() {
101-
init.getInit(index) = this.asExpr()
102-
and index != 0
103-
}
88+
ArrayInitAtNonZeroIndex() {
89+
init.getInit(index) = this.asExpr() and
90+
index != 0
91+
}
10492
}
10593

10694
// Stream.concat(Arrays.stream(array_1), Arrays.stream(array_2))
10795
class StreamConcatAtNonZeroIndex extends DataFlow::Node {
108-
MethodAccess call;
109-
int index;
110-
111-
StreamConcatAtNonZeroIndex() {
112-
call.getMethod().getQualifiedName() = "java.util.stream.Stream.concat"
113-
and call.getArgument(index) = this.asExpr()
114-
and index != 0
115-
}
96+
MethodCall call;
97+
int index;
98+
99+
StreamConcatAtNonZeroIndex() {
100+
call.getMethod().getQualifiedName() = "java.util.stream.Stream.concat" and
101+
call.getArgument(index) = this.asExpr() and
102+
index != 0
103+
}
116104
}
117105

118-
119106
// allow list of executables that execute their arguments
120107
// TODO: extend with data extensions
121108
class UnSafeExecutable extends string {
122-
bindingset[this]
123-
UnSafeExecutable() {
124-
this.regexpMatch("^(|.*/)([a-z]*sh|javac?|python[23]?|perl|[Pp]ower[Ss]hell|php|node|deno|bun|ruby|osascript|cmd|Rscript|groovy)(\\.exe)?$")
125-
and not this.matches("netsh.exe")
126-
}
109+
bindingset[this]
110+
UnSafeExecutable() {
111+
this.regexpMatch("^(|.*/)([a-z]*sh|javac?|python[23]?|perl|[Pp]ower[Ss]hell|php|node|deno|bun|ruby|osascript|cmd|Rscript|groovy)(\\.exe)?$") and
112+
not this.matches("netsh.exe")
113+
}
127114
}

java/lib/qlpack.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ library: true
22
name: githubsecuritylab/codeql-java-libs
33
version: 0.0.1
44
dependencies:
5-
codeql/java-all: '*'
5+
codeql/java-all: '1.0.0'
6+

java/src/codeql-pack.lock.yml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,27 @@
22
lockVersion: 1.0.0
33
dependencies:
44
codeql/dataflow:
5-
version: 0.0.3
5+
version: 1.0.0
66
codeql/java-all:
7-
version: 0.7.4
7+
version: 1.0.0
88
codeql/mad:
9-
version: 0.1.4
9+
version: 1.0.0
10+
codeql/rangeanalysis:
11+
version: 1.0.0
1012
codeql/regex:
11-
version: 0.1.4
13+
version: 1.0.0
1214
codeql/ssa:
13-
version: 0.1.4
15+
version: 1.0.0
16+
codeql/threat-models:
17+
version: 1.0.0
1418
codeql/tutorial:
15-
version: 0.1.4
19+
version: 1.0.0
20+
codeql/typeflow:
21+
version: 1.0.0
1622
codeql/typetracking:
17-
version: 0.1.4
23+
version: 1.0.0
1824
codeql/util:
19-
version: 0.1.4
25+
version: 1.0.0
26+
codeql/xml:
27+
version: 1.0.0
2028
compiled: false

java/src/qlpack.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ version: 0.0.5
44
suites: suites
55
defaultSuiteFile: suites/java.qls
66
dependencies:
7-
codeql/java-all: "*"
7+
codeql/java-all: '1.0.0'
88
githubsecuritylab/codeql-java-libs: 0.0.1

java/src/security/CWE-078/CommandInjectionRuntimeExec.ql

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,46 @@
1010
* external/cwe/cwe-078
1111
*/
1212

13-
import DataFlow::PathGraph
1413
import ghsl.CommandInjectionRuntimeExec
1514

1615
class RemoteSource extends Source {
1716
RemoteSource() { this instanceof RemoteFlowSource }
1817
}
1918

20-
from
21-
DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf,
22-
MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd,
23-
ExecTaintConfiguration confCmd
19+
module Flow = TaintTracking::Global<RuntimeExec::RuntimeExecConfiguration>;
20+
21+
module Flow2 = TaintTracking::Global<ExecTaint::ExecTaintConfiguration>;
22+
23+
module FlowGraph =
24+
DataFlow::MergePathGraph<Flow::PathNode, Flow2::PathNode, Flow::PathGraph, Flow2::PathGraph>;
25+
26+
import FlowGraph::PathGraph
27+
28+
from FlowGraph::PathNode source, FlowGraph::PathNode sink
2429
where
25-
call.getMethod() instanceof RuntimeExecMethod and
26-
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
27-
(
28-
confCmd.hasFlow(sourceCmd, sinkCmd) and
29-
sinkCmd.asExpr() = call.getArgument(0)
30-
) and
31-
// it is tainted by untrusted user input
32-
(
33-
conf.hasFlow(source.getNode(), sink.getNode()) and
34-
sink.getNode().asExpr() = call.getArgument(0)
35-
)
30+
Flow::flowPath(source.asPathNode1(), sink.asPathNode1()) or
31+
Flow2::flowPath(source.asPathNode2(), sink.asPathNode2())
3632
select sink, source, sink,
3733
"Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
38-
sourceCmd, sourceCmd.toString(), source.getNode(), source.toString()
34+
source, source.toString(), source.getNode(), source.toString()
35+
//
36+
//
37+
// from
38+
// DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf,
39+
// MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd,
40+
// ExecTaintConfiguration confCmd
41+
// where
42+
// call.getMethod() instanceof RuntimeExecMethod and
43+
// // this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
44+
// (
45+
// confCmd.hasFlow(sourceCmd, sinkCmd) and
46+
// sinkCmd.asExpr() = call.getArgument(0)
47+
// ) and
48+
// // it is tainted by untrusted user input
49+
// (
50+
// conf.hasFlow(source.getNode(), sink.getNode()) and
51+
// sink.getNode().asExpr() = call.getArgument(0)
52+
// )
53+
// select sink, source, sink,
54+
// "Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
55+
// sourceCmd, sourceCmd.toString(), source.getNode(), source.toString()

java/test/codeql-pack.lock.yml

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,31 @@
22
lockVersion: 1.0.0
33
dependencies:
44
codeql/dataflow:
5-
version: 0.0.3
5+
version: 1.0.0
66
codeql/java-all:
7-
version: 0.7.4
7+
version: 1.0.0
88
codeql/java-queries:
9-
version: 0.7.4
9+
version: 1.0.0
1010
codeql/mad:
11-
version: 0.1.4
11+
version: 1.0.0
12+
codeql/rangeanalysis:
13+
version: 1.0.0
1214
codeql/regex:
13-
version: 0.1.4
15+
version: 1.0.0
1416
codeql/ssa:
15-
version: 0.1.4
17+
version: 1.0.0
1618
codeql/suite-helpers:
17-
version: 0.6.4
19+
version: 1.0.0
20+
codeql/threat-models:
21+
version: 1.0.0
1822
codeql/tutorial:
19-
version: 0.1.4
23+
version: 1.0.0
24+
codeql/typeflow:
25+
version: 1.0.0
2026
codeql/typetracking:
21-
version: 0.1.4
27+
version: 1.0.0
2228
codeql/util:
23-
version: 0.1.4
29+
version: 1.0.0
30+
codeql/xml:
31+
version: 1.0.0
2432
compiled: false

0 commit comments

Comments
 (0)