Skip to content

Commit f3ef93f

Browse files
committed
Make sinks more specific, improve tests
1 parent f9e6b3c commit f3ef93f

File tree

4 files changed

+567
-39
lines changed

4 files changed

+567
-39
lines changed

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
/**
2-
* Provides classes and predicates for Groovy Code Injection
3-
* taint-tracking configuration.
4-
*/
1+
/** Provides classes to reason about Groovy code injection attacks. */
52

63
import java
74
import semmle.code.java.dataflow.DataFlow
@@ -58,7 +55,12 @@ private class DefaultLdapInjectionSinkModel extends SinkModelCsv {
5855
"groovy.util;Eval;false;x;(Object,String);;Argument[1];groovy",
5956
"groovy.util;Eval;false;xy;(Object,Object,String);;Argument[2];groovy",
6057
"groovy.util;Eval;false;xyz;(Object,Object,Object,String);;Argument[3];groovy",
61-
"groovy.lang;GroovyClassLoader;false;parseClass;;;Argument[0];groovy",
58+
"groovy.lang;GroovyClassLoader;false;parseClass;(GroovyCodeSource);;Argument[0];groovy",
59+
"groovy.lang;GroovyClassLoader;false;parseClass;(GroovyCodeSource,boolean);;Argument[0];groovy",
60+
"groovy.lang;GroovyClassLoader;false;parseClass;(InputStream,String);;Argument[0];groovy",
61+
"groovy.lang;GroovyClassLoader;false;parseClass;(Reader,String);;Argument[0];groovy",
62+
"groovy.lang;GroovyClassLoader;false;parseClass;(String);;Argument[0];groovy",
63+
"groovy.lang;GroovyClassLoader;false;parseClass;(String,String);;Argument[0];groovy",
6264
"org.codehaus.groovy.control;CompilationUnit;false;compile;;;Argument[-1];groovy"
6365
]
6466
}

java/ql/test/query-tests/security/CWE-094/GroovyClassLoaderTest.java

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,54 @@
1-
import groovy.lang.GroovyClassLoader;
2-
import groovy.lang.GroovyCodeSource;
3-
import groovy.lang.GroovyObject;
4-
1+
import java.io.ByteArrayInputStream;
2+
import java.io.IOException;
3+
import java.io.StringReader;
54
import javax.servlet.ServletException;
65
import javax.servlet.http.HttpServlet;
76
import javax.servlet.http.HttpServletRequest;
87
import javax.servlet.http.HttpServletResponse;
9-
import java.io.IOException;
8+
import groovy.lang.GroovyClassLoader;
9+
import groovy.lang.GroovyCodeSource;
1010

1111
public class GroovyClassLoaderTest extends HttpServlet {
1212

1313
protected void doGet(HttpServletRequest request, HttpServletResponse response)
1414
throws ServletException, IOException {
15-
// "groovy.lang;GroovyClassLoader;false;parseClass;;;Argument[0];groovy",
16-
try {
15+
// "groovy.lang;GroovyClassLoader;false;parseClass;(GroovyCodeSource);;Argument[0];groovy",
16+
{
1717
String script = request.getParameter("script");
1818
final GroovyClassLoader classLoader = new GroovyClassLoader();
19-
Class groovy = classLoader.parseClass(script); // $hasGroovyInjection
20-
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
21-
22-
} catch (Exception e) {
23-
// Ignore
19+
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
20+
classLoader.parseClass(gcs); // $hasGroovyInjection
2421
}
25-
try {
22+
// "groovy.lang;GroovyClassLoader;false;parseClass;(GroovyCodeSource,boolean);;Argument[0];groovy",
23+
{
2624
String script = request.getParameter("script");
2725
final GroovyClassLoader classLoader = new GroovyClassLoader();
2826
GroovyCodeSource gcs = new GroovyCodeSource(script, "test", "Test");
29-
Class groovy = classLoader.parseClass(gcs); // $hasGroovyInjection
30-
GroovyObject groovyObj = (GroovyObject) groovy.newInstance();
31-
} catch (Exception e) {
32-
// Ignore
27+
classLoader.parseClass(gcs, true); // $hasGroovyInjection
28+
}
29+
// "groovy.lang;GroovyClassLoader;false;parseClass;(InputStream,String);;Argument[0];groovy",
30+
{
31+
String script = request.getParameter("script");
32+
final GroovyClassLoader classLoader = new GroovyClassLoader();
33+
classLoader.parseClass(new ByteArrayInputStream(script.getBytes()), "test"); // $hasGroovyInjection
34+
}
35+
// "groovy.lang;GroovyClassLoader;false;parseClass;(Reader,String);;Argument[0];groovy",
36+
{
37+
String script = request.getParameter("script");
38+
final GroovyClassLoader classLoader = new GroovyClassLoader();
39+
classLoader.parseClass(new StringReader(script), "test"); // $hasGroovyInjection
40+
}
41+
// "groovy.lang;GroovyClassLoader;false;parseClass;(String);;Argument[0];groovy",
42+
{
43+
String script = request.getParameter("script");
44+
final GroovyClassLoader classLoader = new GroovyClassLoader();
45+
classLoader.parseClass(script); // $hasGroovyInjection
46+
}
47+
// "groovy.lang;GroovyClassLoader;false;parseClass;(String,String);;Argument[0];groovy",
48+
{
49+
String script = request.getParameter("script");
50+
final GroovyClassLoader classLoader = new GroovyClassLoader();
51+
classLoader.parseClass(script, "test"); // $hasGroovyInjection
3352
}
3453
}
3554
}
Lines changed: 272 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,287 @@
11
/*
2-
* Licensed to the Apache Software Foundation (ASF) under one
3-
* or more contributor license agreements. See the NOTICE file
4-
* distributed with this work for additional information
5-
* regarding copyright ownership. The ASF licenses this file
6-
* to you under the Apache License, Version 2.0 (the
7-
* "License"); you may not use this file except in compliance
8-
* with the License. You may obtain a copy of the License at
2+
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
3+
* agreements. See the NOTICE file distributed with this work for additional information regarding
4+
* copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
5+
* "License"); you may not use this file except in compliance with the License. You may obtain a
6+
* copy of the License at
97
*
10-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software distributed under the License
11+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12+
* or implied. See the License for the specific language governing permissions and limitations under
13+
* the License.
14+
*/
15+
/*
16+
* @todo multi threaded compiling of the same class but with different roots for compilation... T1
17+
* compiles A, which uses B, T2 compiles B... mark A and B as parsed and then synchronize
18+
* compilation. Problems: How to synchronize? How to get error messages?
1119
*
12-
* Unless required by applicable law or agreed to in writing,
13-
* software distributed under the License is distributed on an
14-
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15-
* KIND, either express or implied. See the License for the
16-
* specific language governing permissions and limitations
17-
* under the License.
1820
*/
1921
package groovy.lang;
2022

21-
public class GroovyClassLoader {
23+
import java.io.File;
24+
import java.io.IOException;
25+
import java.io.InputStream;
26+
import java.io.Reader;
27+
import java.net.URL;
28+
import java.net.URLClassLoader;
29+
import java.util.Enumeration;
30+
import org.codehaus.groovy.ast.ClassNode;
31+
import org.codehaus.groovy.control.CompilationFailedException;
32+
import org.codehaus.groovy.control.CompilerConfiguration;
33+
34+
public class GroovyClassLoader extends URLClassLoader {
2235
public GroovyClassLoader() {
36+
super(null);
37+
}
38+
39+
public GroovyClassLoader(ClassLoader loader) {
40+
super(null);
41+
}
42+
43+
public GroovyClassLoader(GroovyClassLoader parent) {
44+
super(null);
45+
}
46+
47+
public GroovyClassLoader(ClassLoader parent, CompilerConfiguration config,
48+
boolean useConfigurationClasspath) {
49+
super(null);
50+
}
51+
52+
public GroovyClassLoader(ClassLoader loader, CompilerConfiguration config) {
53+
super(null);
54+
}
55+
56+
57+
public Class defineClass(ClassNode classNode, String file, String newCodeBase) {
58+
return null;
59+
}
60+
61+
public boolean hasCompatibleConfiguration(CompilerConfiguration config) {
62+
return false;
63+
}
64+
65+
public Class parseClass(File file) throws CompilationFailedException, IOException {
66+
return null;
67+
}
68+
69+
public Class parseClass(final String text, final String fileName)
70+
throws CompilationFailedException {
71+
return null;
72+
}
73+
74+
public Class parseClass(String text) throws CompilationFailedException {
75+
return null;
76+
}
77+
78+
public synchronized String generateScriptName() {
79+
return null;
80+
}
81+
82+
public Class parseClass(final Reader reader, final String fileName)
83+
throws CompilationFailedException {
84+
return null;
85+
}
86+
87+
public Class parseClass(final InputStream in, final String fileName)
88+
throws CompilationFailedException {
89+
return null;
90+
}
91+
92+
public Class parseClass(GroovyCodeSource codeSource) throws CompilationFailedException {
93+
return null;
94+
}
95+
96+
public Class parseClass(final GroovyCodeSource codeSource, boolean shouldCacheSource)
97+
throws CompilationFailedException {
98+
return null;
99+
}
100+
101+
public static class InnerLoader extends GroovyClassLoader {
102+
public InnerLoader(GroovyClassLoader delegate) {}
103+
104+
@Override
105+
public void addClasspath(String path) {}
106+
107+
@Override
108+
public void clearCache() {}
109+
110+
@Override
111+
public URL findResource(String name) {
112+
return null;
113+
}
114+
115+
@Override
116+
public Enumeration<URL> findResources(String name) throws IOException {
117+
return null;
118+
}
119+
120+
@Override
121+
public Class[] getLoadedClasses() {
122+
return null;
123+
}
124+
125+
@Override
126+
public URL getResource(String name) {
127+
return null;
128+
}
129+
130+
@Override
131+
public InputStream getResourceAsStream(String name) {
132+
return null;
133+
}
134+
135+
@Override
136+
public URL[] getURLs() {
137+
return null;
138+
}
139+
140+
@Override
141+
public Class loadClass(String name, boolean lookupScriptFiles,
142+
boolean preferClassOverScript, boolean resolve)
143+
throws ClassNotFoundException, CompilationFailedException {
144+
return null;
145+
}
146+
147+
@Override
148+
public Class parseClass(GroovyCodeSource codeSource, boolean shouldCache)
149+
throws CompilationFailedException {
150+
return null;
151+
}
152+
153+
@Override
154+
public void addURL(URL url) {}
155+
156+
@Override
157+
public Class defineClass(ClassNode classNode, String file, String newCodeBase) {
158+
return null;
159+
}
160+
161+
@Override
162+
public Class parseClass(File file) throws CompilationFailedException, IOException {
163+
return null;
164+
}
165+
166+
@Override
167+
public Class parseClass(String text, String fileName) throws CompilationFailedException {
168+
return null;
169+
}
170+
171+
@Override
172+
public Class parseClass(String text) throws CompilationFailedException {
173+
return null;
174+
}
175+
176+
@Override
177+
public String generateScriptName() {
178+
return null;
179+
}
180+
181+
@Override
182+
public Class parseClass(Reader reader, String fileName) throws CompilationFailedException {
183+
return null;
184+
}
185+
186+
@Override
187+
public Class parseClass(InputStream in, String fileName) throws CompilationFailedException {
188+
return null;
189+
}
190+
191+
@Override
192+
public Class parseClass(GroovyCodeSource codeSource) throws CompilationFailedException {
193+
return null;
194+
}
195+
196+
@Override
197+
public Class defineClass(String name, byte[] b) {
198+
return null;
199+
}
200+
201+
@Override
202+
public Class loadClass(String name, boolean lookupScriptFiles,
203+
boolean preferClassOverScript)
204+
throws ClassNotFoundException, CompilationFailedException {
205+
return null;
206+
}
207+
208+
@Override
209+
public void setShouldRecompile(Boolean mode) {}
210+
211+
@Override
212+
public Boolean isShouldRecompile() {
213+
return null;
214+
}
215+
216+
@Override
217+
public Class<?> loadClass(String name) throws ClassNotFoundException {
218+
return null;
219+
}
220+
221+
@Override
222+
public Enumeration<URL> getResources(String name) throws IOException {
223+
return null;
224+
}
225+
226+
@Override
227+
public void setDefaultAssertionStatus(boolean enabled) {}
228+
229+
@Override
230+
public void setPackageAssertionStatus(String packageName, boolean enabled) {}
231+
232+
@Override
233+
public void setClassAssertionStatus(String className, boolean enabled) {}
234+
235+
@Override
236+
public void clearAssertionStatus() {}
237+
238+
@Override
239+
public void close() throws IOException {}
240+
241+
public long getTimeStamp() {
242+
return 0;
243+
}
244+
245+
}
246+
247+
public Class defineClass(String name, byte[] b) {
248+
return null;
23249
}
24250

25-
public Class parseClass(String text) {
251+
public Class loadClass(final String name, boolean lookupScriptFiles,
252+
boolean preferClassOverScript)
253+
throws ClassNotFoundException, CompilationFailedException {
26254
return null;
27255
}
28256

29-
public Class parseClass(GroovyCodeSource gcs) {
257+
public void addURL(URL url) {}
258+
259+
public void setShouldRecompile(Boolean mode) {}
260+
261+
public Boolean isShouldRecompile() {
30262
return null;
31263
}
264+
265+
public Class loadClass(final String name, boolean lookupScriptFiles,
266+
boolean preferClassOverScript, boolean resolve)
267+
throws ClassNotFoundException, CompilationFailedException {
268+
return null;
269+
}
270+
271+
@Override
272+
public Class<?> loadClass(String name) throws ClassNotFoundException {
273+
return null;
274+
}
275+
276+
public void addClasspath(final String path) {}
277+
278+
public Class[] getLoadedClasses() {
279+
return null;
280+
}
281+
282+
public void clearCache() {}
283+
284+
@Override
285+
public void close() throws IOException {}
286+
32287
}

0 commit comments

Comments
 (0)