Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FIXED JENKINS-25348]
Added necessary additions.
Now the clients of this plugin needs to be modified to use this newly added method.
  • Loading branch information
kohsuke committed Nov 4, 2014
1 parent c014c29 commit 492dca1
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 0 deletions.
Expand Up @@ -43,13 +43,33 @@ public class GroovySandbox {

/**
* Prepares a compiler configuration the sandbox.
*
* <h2>CAUTION</h2>
* <p>
* When creating {@link GroovyShell} with this {@link CompilerConfiguration},
* you also have to use {@link #createSecureClassLoader(ClassLoader)} to wrap
* a classloader of your choice into sandbox-aware one.
*
* <p>
* Otherwise the classloader that you provide to {@link GroovyShell} might
* have its own copy of groovy-sandbox, which lets the code escape the sandbox.
*
* @return a compiler configuration set up to use the sandbox
*/
public static @Nonnull CompilerConfiguration createSecureCompilerConfiguration() {
CompilerConfiguration cc = new CompilerConfiguration();
cc.addCompilationCustomizers(new SandboxTransformer());
return cc;
}

/**
* Prepares a classloader for Groovy shell for sandboxing.
*
* See {@link #createSecureCompilerConfiguration()} for the discussion.
*/
public static @Nonnull ClassLoader createSecureClassLoader(ClassLoader base) {
return new SandboxResolvingClassLoader(base);
}

/**
* Runs a block in the sandbox.
Expand Down
@@ -0,0 +1,26 @@
package org.jenkinsci.plugins.scriptsecurity.sandbox.groovy;

import groovy.lang.GroovyShell;

/**
* Makes sure that the class references to groovy-sandbox resolves to our own copy of
* <tt>groovy-sandbox.jar</tt> instead of the random one picked up by the classloader
* given to {@link GroovyShell} via the constructor.
*
* @see <a href="https://issues.jenkins-ci.org/browse/JENKINS-25348">JENKINS-25438</a>
* @author Kohsuke Kawaguchi
*/
class SandboxResolvingClassLoader extends ClassLoader {
public SandboxResolvingClassLoader(ClassLoader parent) {
super(parent);
}

@Override
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith("org.kohsuke.groovy.sandbox.")) {
return this.getClass().getClassLoader().loadClass(name);
} else {
return super.loadClass(name, resolve);
}
}
}
Expand Up @@ -154,6 +154,7 @@ public Object evaluate(ClassLoader loader, Binding binding) throws Exception {

loader = new URLClassLoader(urlList.toArray(new URL[urlList.size()]), loader);
}
loader = GroovySandbox.createSecureClassLoader(loader);
if (sandbox) {
GroovyShell shell = new GroovyShell(loader, binding, GroovySandbox.createSecureCompilerConfiguration());
try {
Expand Down
Expand Up @@ -24,6 +24,10 @@

package org.jenkinsci.plugins.scriptsecurity.sandbox.groovy;

import groovy.lang.Binding;
import hudson.remoting.Which;
import org.apache.tools.ant.AntClassLoader;
import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
import org.jenkinsci.plugins.scriptsecurity.scripts.ClasspathEntry;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
Expand Down Expand Up @@ -53,7 +57,9 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.kohsuke.groovy.sandbox.impl.Checker;

public class SecureGroovyScriptTest {

Expand Down Expand Up @@ -716,4 +722,24 @@ private List<File> getAllUpdatedJarFiles() throws URISyntaxException {
assertEquals(0, ScriptApproval.get().getApprovedClasspathEntries().size());
}
}

@Test @Issue("JENKINS-25348")
public void testSandboxClassResolution() throws Exception {
File jar = Which.jarFile(Checker.class);

// this child-first classloader creates an environment in which another groovy-sandbox exists
AntClassLoader a = new AntClassLoader(getClass().getClassLoader(),false);
a.addPathComponent(jar);

// make sure we are loading two different copies now
assertNotSame(Checker.class, a.loadClass(Checker.class.getName()));

SecureGroovyScript sgs = new SecureGroovyScript("System.gc()", true, null);
try {
sgs.configuringWithKeyItem().evaluate(a, new Binding());
fail("Expecting a rejection");
} catch (RejectedAccessException e) {
assertTrue(e.getMessage().contains("staticMethod java.lang.System gc"));
}
}
}

0 comments on commit 492dca1

Please sign in to comment.