Skip to content

Commit 0f19960

Browse files
committed
Refactor GroovyInjection.qll
1 parent 45a72ff commit 0f19960

File tree

4 files changed

+172
-172
lines changed

4 files changed

+172
-172
lines changed

java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ private module Frameworks {
9696
private import semmle.code.java.frameworks.spring.SpringWebMultipart
9797
private import semmle.code.java.security.ResponseSplitting
9898
private import semmle.code.java.security.InformationLeak
99+
private import semmle.code.java.security.GroovyInjection
99100
private import semmle.code.java.security.JexlInjectionSinkModels
100101
private import semmle.code.java.security.LdapInjection
101102
private import semmle.code.java.security.XPath
102-
private import semmle.code.java.security.GroovyInjectionSinkModels
103103
private import semmle.code.java.frameworks.android.SQLite
104104
private import semmle.code.java.frameworks.Jdbc
105105
private import semmle.code.java.frameworks.SpringJdbc
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/** Provides classes to reason about Groovy code injection attacks. */
2+
3+
import semmle.code.java.dataflow.DataFlow
4+
import semmle.code.java.dataflow.ExternalFlow
5+
import semmle.code.java.frameworks.Networking
6+
7+
/** A data flow sink for Groovy expression injection vulnerabilities. */
8+
abstract class GroovyInjectionSink extends DataFlow::ExprNode { }
9+
10+
/**
11+
* A unit class for adding additional taint steps.
12+
*
13+
* Extend this class to add additional taint steps that should apply to the `GroovyInjectionConfig`.
14+
*/
15+
class GroovyInjectionAdditionalTaintStep extends Unit {
16+
/**
17+
* Holds if the step from `node1` to `node2` should be considered a taint
18+
* step for the `GroovyInjectionConfig` configuration.
19+
*/
20+
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
21+
}
22+
23+
private class DefaultGroovyInjectionSink extends GroovyInjectionSink {
24+
DefaultGroovyInjectionSink() { sinkNode(this, "groovy") }
25+
}
26+
27+
private class DefaultGroovyInjectionSinkModel extends SinkModelCsv {
28+
override predicate row(string row) {
29+
row =
30+
[
31+
// Signatures are specified to exclude sinks of the type `File`
32+
"groovy.lang;GroovyShell;false;evaluate;(GroovyCodeSource);;Argument[0];groovy",
33+
"groovy.lang;GroovyShell;false;evaluate;(Reader);;Argument[0];groovy",
34+
"groovy.lang;GroovyShell;false;evaluate;(Reader,String);;Argument[0];groovy",
35+
"groovy.lang;GroovyShell;false;evaluate;(String);;Argument[0];groovy",
36+
"groovy.lang;GroovyShell;false;evaluate;(String,String);;Argument[0];groovy",
37+
"groovy.lang;GroovyShell;false;evaluate;(String,String,String);;Argument[0];groovy",
38+
"groovy.lang;GroovyShell;false;evaluate;(URI);;Argument[0];groovy",
39+
"groovy.lang;GroovyShell;false;parse;(Reader);;Argument[0];groovy",
40+
"groovy.lang;GroovyShell;false;parse;(Reader,String);;Argument[0];groovy",
41+
"groovy.lang;GroovyShell;false;parse;(String);;Argument[0];groovy",
42+
"groovy.lang;GroovyShell;false;parse;(String,String);;Argument[0];groovy",
43+
"groovy.lang;GroovyShell;false;parse;(URI);;Argument[0];groovy",
44+
"groovy.lang;GroovyShell;false;run;(GroovyCodeSource,String[]);;Argument[0];groovy",
45+
"groovy.lang;GroovyShell;false;run;(GroovyCodeSource,List);;Argument[0];groovy",
46+
"groovy.lang;GroovyShell;false;run;(Reader,String,String[]);;Argument[0];groovy",
47+
"groovy.lang;GroovyShell;false;run;(Reader,String,List);;Argument[0];groovy",
48+
"groovy.lang;GroovyShell;false;run;(String,String,String[]);;Argument[0];groovy",
49+
"groovy.lang;GroovyShell;false;run;(String,String,List);;Argument[0];groovy",
50+
"groovy.lang;GroovyShell;false;run;(URI,String[]);;Argument[0];groovy",
51+
"groovy.lang;GroovyShell;false;run;(URI,List);;Argument[0];groovy",
52+
"groovy.util;Eval;false;me;(String);;Argument[0];groovy",
53+
"groovy.util;Eval;false;me;(String,Object,String);;Argument[2];groovy",
54+
"groovy.util;Eval;false;x;(Object,String);;Argument[1];groovy",
55+
"groovy.util;Eval;false;xy;(Object,Object,String);;Argument[2];groovy",
56+
"groovy.util;Eval;false;xyz;(Object,Object,Object,String);;Argument[3];groovy",
57+
"groovy.lang;GroovyClassLoader;false;parseClass;(GroovyCodeSource);;Argument[0];groovy",
58+
"groovy.lang;GroovyClassLoader;false;parseClass;(GroovyCodeSource,boolean);;Argument[0];groovy",
59+
"groovy.lang;GroovyClassLoader;false;parseClass;(InputStream,String);;Argument[0];groovy",
60+
"groovy.lang;GroovyClassLoader;false;parseClass;(Reader,String);;Argument[0];groovy",
61+
"groovy.lang;GroovyClassLoader;false;parseClass;(String);;Argument[0];groovy",
62+
"groovy.lang;GroovyClassLoader;false;parseClass;(String,String);;Argument[0];groovy",
63+
"org.codehaus.groovy.control;CompilationUnit;false;compile;;;Argument[-1];groovy"
64+
]
65+
}
66+
}
67+
68+
/** A set of additional taint steps to consider when taint tracking Groovy related data flows. */
69+
private class DefaultGroovyInjectionAdditionalTaintStep extends GroovyInjectionAdditionalTaintStep {
70+
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
71+
groovyCodeSourceTaintStep(node1, node2) or
72+
groovyCompilationUnitTaintStep(node1, node2) or
73+
groovySourceUnitTaintStep(node1, node2) or
74+
groovyReaderSourceTaintStep(node1, node2)
75+
}
76+
}
77+
78+
/**
79+
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted string to
80+
* a `GroovyCodeSource` instance by calling `new GroovyCodeSource(tainted, ...)`.
81+
*/
82+
private predicate groovyCodeSourceTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
83+
exists(ConstructorCall gcscc |
84+
gcscc.getConstructedType() instanceof TypeGroovyCodeSource and
85+
gcscc = toNode.asExpr() and
86+
gcscc.getArgument(0) = fromNode.asExpr()
87+
)
88+
}
89+
90+
/**
91+
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted object to
92+
* a `CompilationUnit` instance by calling `compilationUnit.addSource(..., tainted)`.
93+
*/
94+
private predicate groovyCompilationUnitTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
95+
exists(MethodAccess ma, Method m |
96+
ma.getMethod() = m and
97+
m.hasName("addSource") and
98+
m.getDeclaringType() instanceof TypeGroovyCompilationUnit
99+
|
100+
fromNode.asExpr() = ma.getArgument(ma.getNumArgument() - 1) and
101+
toNode.asExpr() = ma.getQualifier()
102+
)
103+
}
104+
105+
/**
106+
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted object to
107+
* a `SourceUnit` instance by calling `new SourceUnit(..., tainted, ...)`
108+
* or `SourceUnit.create(..., tainted)`
109+
*/
110+
private predicate groovySourceUnitTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
111+
exists(ClassInstanceExpr cie, Argument arg, int index |
112+
cie.getConstructedType() instanceof TypeGroovySourceUnit and
113+
arg = cie.getArgument(index) and
114+
(
115+
index = 0 and arg.getType() instanceof TypeUrl
116+
or
117+
index = 1 and
118+
(
119+
arg.getType() instanceof TypeString or
120+
arg.getType() instanceof TypeReaderSource
121+
)
122+
)
123+
|
124+
fromNode.asExpr() = arg and
125+
toNode.asExpr() = cie
126+
)
127+
or
128+
exists(MethodAccess ma, Method m |
129+
ma.getMethod() = m and
130+
m.hasName("create") and
131+
m.getDeclaringType() instanceof TypeGroovySourceUnit
132+
|
133+
fromNode.asExpr() = ma.getArgument(1) and toNode.asExpr() = ma
134+
)
135+
}
136+
137+
/**
138+
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted object to
139+
* a `ReaderSource` instance by calling `new *ReaderSource(tainted, ...)`
140+
*/
141+
private predicate groovyReaderSourceTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
142+
exists(ClassInstanceExpr cie | cie.getConstructedType() instanceof TypeReaderSource |
143+
fromNode.asExpr() = cie.getArgument(0) and toNode.asExpr() = cie
144+
)
145+
}
146+
147+
/** The class `groovy.lang.GroovyCodeSource`. */
148+
private class TypeGroovyCodeSource extends RefType {
149+
TypeGroovyCodeSource() { this.hasQualifiedName("groovy.lang", "GroovyCodeSource") }
150+
}
151+
152+
/** The class `org.codehaus.groovy.control.CompilationUnit`. */
153+
private class TypeGroovyCompilationUnit extends RefType {
154+
TypeGroovyCompilationUnit() {
155+
this.hasQualifiedName("org.codehaus.groovy.control", "CompilationUnit")
156+
}
157+
}
158+
159+
/** The class `org.codehaus.groovy.control.CompilationUnit`. */
160+
private class TypeGroovySourceUnit extends RefType {
161+
TypeGroovySourceUnit() { this.hasQualifiedName("org.codehaus.groovy.control", "SourceUnit") }
162+
}
163+
164+
/** The class `org.codehaus.groovy.control.io.ReaderSource`. */
165+
private class TypeReaderSource extends RefType {
166+
TypeReaderSource() {
167+
this.getASupertype*().hasQualifiedName("org.codehaus.groovy.control.io", "ReaderSource")
168+
}
169+
}
Lines changed: 2 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,9 @@
1-
/** Provides classes to reason about Groovy code injection attacks. */
1+
/** Provides taint tracking configurations relating to Groovy injection vulnerabilities. */
22

33
import java
4-
import semmle.code.java.dataflow.DataFlow
5-
import semmle.code.java.dataflow.ExternalFlow
64
import semmle.code.java.dataflow.FlowSources
75
import semmle.code.java.dataflow.TaintTracking
8-
import semmle.code.java.frameworks.Networking
9-
10-
/** A data flow sink for Groovy expression injection vulnerabilities. */
11-
abstract class GroovyInjectionSink extends DataFlow::ExprNode { }
12-
13-
/**
14-
* A unit class for adding additional taint steps.
15-
*
16-
* Extend this class to add additional taint steps that should apply to the `GroovyInjectionConfig`.
17-
*/
18-
class GroovyInjectionAdditionalTaintStep extends Unit {
19-
/**
20-
* Holds if the step from `node1` to `node2` should be considered a taint
21-
* step for the `GroovyInjectionConfig` configuration.
22-
*/
23-
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
24-
}
25-
26-
private class DefaultGroovyInjectionSink extends GroovyInjectionSink {
27-
DefaultGroovyInjectionSink() { sinkNode(this, "groovy") }
28-
}
29-
30-
/** A set of additional taint steps to consider when taint tracking Groovy related data flows. */
31-
private class DefaultGroovyInjectionAdditionalTaintStep extends GroovyInjectionAdditionalTaintStep {
32-
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
33-
groovyCodeSourceTaintStep(node1, node2) or
34-
groovyCompilationUnitTaintStep(node1, node2) or
35-
groovySourceUnitTaintStep(node1, node2) or
36-
groovyReaderSourceTaintStep(node1, node2)
37-
}
38-
}
6+
import semmle.code.java.security.GroovyInjection
397

408
/**
419
* A taint-tracking configuration for unsafe user input
@@ -52,96 +20,3 @@ class GroovyInjectionConfig extends TaintTracking::Configuration {
5220
any(GroovyInjectionAdditionalTaintStep c).step(fromNode, toNode)
5321
}
5422
}
55-
56-
/**
57-
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted string to
58-
* a `GroovyCodeSource` instance by calling `new GroovyCodeSource(tainted, ...)`.
59-
*/
60-
private predicate groovyCodeSourceTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
61-
exists(ConstructorCall gcscc |
62-
gcscc.getConstructedType() instanceof TypeGroovyCodeSource and
63-
gcscc = toNode.asExpr() and
64-
gcscc.getArgument(0) = fromNode.asExpr()
65-
)
66-
}
67-
68-
/**
69-
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted object to
70-
* a `CompilationUnit` instance by calling `compilationUnit.addSource(..., tainted)`.
71-
*/
72-
private predicate groovyCompilationUnitTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
73-
exists(MethodAccess ma, Method m |
74-
ma.getMethod() = m and
75-
m.hasName("addSource") and
76-
m.getDeclaringType() instanceof TypeGroovyCompilationUnit
77-
|
78-
fromNode.asExpr() = ma.getArgument(ma.getNumArgument() - 1) and
79-
toNode.asExpr() = ma.getQualifier()
80-
)
81-
}
82-
83-
/**
84-
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted object to
85-
* a `SourceUnit` instance by calling `new SourceUnit(..., tainted, ...)`
86-
* or `SourceUnit.create(..., tainted)`
87-
*/
88-
private predicate groovySourceUnitTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
89-
exists(ClassInstanceExpr cie, Argument arg, int index |
90-
cie.getConstructedType() instanceof TypeGroovySourceUnit and
91-
arg = cie.getArgument(index) and
92-
(
93-
index = 0 and arg.getType() instanceof TypeUrl
94-
or
95-
index = 1 and
96-
(
97-
arg.getType() instanceof TypeString or
98-
arg.getType() instanceof TypeReaderSource
99-
)
100-
)
101-
|
102-
fromNode.asExpr() = arg and
103-
toNode.asExpr() = cie
104-
)
105-
or
106-
exists(MethodAccess ma, Method m |
107-
ma.getMethod() = m and
108-
m.hasName("create") and
109-
m.getDeclaringType() instanceof TypeGroovySourceUnit
110-
|
111-
fromNode.asExpr() = ma.getArgument(1) and toNode.asExpr() = ma
112-
)
113-
}
114-
115-
/**
116-
* Holds if `fromNode` to `toNode` is a dataflow step from a tainted object to
117-
* a `ReaderSource` instance by calling `new *ReaderSource(tainted, ...)`
118-
*/
119-
private predicate groovyReaderSourceTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
120-
exists(ClassInstanceExpr cie | cie.getConstructedType() instanceof TypeReaderSource |
121-
fromNode.asExpr() = cie.getArgument(0) and toNode.asExpr() = cie
122-
)
123-
}
124-
125-
/** The class `groovy.lang.GroovyCodeSource`. */
126-
private class TypeGroovyCodeSource extends RefType {
127-
TypeGroovyCodeSource() { this.hasQualifiedName("groovy.lang", "GroovyCodeSource") }
128-
}
129-
130-
/** The class `org.codehaus.groovy.control.CompilationUnit`. */
131-
private class TypeGroovyCompilationUnit extends RefType {
132-
TypeGroovyCompilationUnit() {
133-
this.hasQualifiedName("org.codehaus.groovy.control", "CompilationUnit")
134-
}
135-
}
136-
137-
/** The class `org.codehaus.groovy.control.CompilationUnit`. */
138-
private class TypeGroovySourceUnit extends RefType {
139-
TypeGroovySourceUnit() { this.hasQualifiedName("org.codehaus.groovy.control", "SourceUnit") }
140-
}
141-
142-
/** The class `org.codehaus.groovy.control.io.ReaderSource`. */
143-
private class TypeReaderSource extends RefType {
144-
TypeReaderSource() {
145-
this.getASupertype*().hasQualifiedName("org.codehaus.groovy.control.io", "ReaderSource")
146-
}
147-
}

java/ql/src/semmle/code/java/security/GroovyInjectionSinkModels.qll

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)