msrb pushed to jenkins-matrix-project-plugin (f21). "Fix SECURITY-125 (..more)"

notifications at fedoraproject.org notifications at fedoraproject.org
Wed Apr 1 16:37:16 UTC 2015


>From 7c978515519cbaf49b7c26b65f48bfe7be97d6bd Mon Sep 17 00:00:00 2001
From: Michal Srb <msrb at redhat.com>
Date: Sun, 29 Mar 2015 16:22:23 +0200
Subject: Fix SECURITY-125

- Resolves: CVE-2015-1806

diff --git a/0001-Fix-SECURITY-125.patch b/0001-Fix-SECURITY-125.patch
new file mode 100644
index 0000000..cf36697
--- /dev/null
+++ b/0001-Fix-SECURITY-125.patch
@@ -0,0 +1,284 @@
+From 002668ed111a5642110932154bab6c5adbdf709c Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Sun, 29 Mar 2015 16:15:20 +0200
+Subject: [PATCH] Fix SECURITY-125
+
+---
+ pom.xml                                            |  7 +++-
+ src/main/java/hudson/matrix/Combination.java       | 14 -------
+ src/main/java/hudson/matrix/FilterScript.java      | 48 ++++++++++++++--------
+ .../CombinationFilterUsingBuildParamsTest.java     |  7 +++-
+ src/test/java/hudson/matrix/CombinationTest.java   |  6 +--
+ src/test/java/hudson/matrix/MatrixTest.java        | 37 +++++++++++++++++
+ 6 files changed, 83 insertions(+), 36 deletions(-)
+
+diff --git a/pom.xml b/pom.xml
+index 5d7a058..12dcffd 100644
+--- a/pom.xml
++++ b/pom.xml
+@@ -3,7 +3,7 @@
+     <parent>
+         <groupId>org.jenkins-ci.plugins</groupId>
+         <artifactId>plugin</artifactId>
+-        <version>1.561</version>
++        <version>1.590</version>
+     </parent>
+     <artifactId>matrix-project</artifactId>
+     <version>1.4</version>
+@@ -72,6 +72,11 @@
+                 </exclusion>
+             </exclusions>
+         </dependency>
++        <dependency>
++            <groupId>org.jenkins-ci.plugins</groupId>
++            <artifactId>script-security</artifactId>
++            <version>1.13</version>
++        </dependency>
+     </dependencies>
+     <build>
+         <plugins>
+diff --git a/src/main/java/hudson/matrix/Combination.java b/src/main/java/hudson/matrix/Combination.java
+index 9ce0a4d..35d3458 100644
+--- a/src/main/java/hudson/matrix/Combination.java
++++ b/src/main/java/hudson/matrix/Combination.java
+@@ -248,18 +248,4 @@ public final class Combination extends TreeMap<String,String> implements Compara
+     public String remove(Object key) {
+         throw new UnsupportedOperationException();
+     }
+-
+-    /**
+-     * Duck-typing for boolean expressions.
+-     *
+-     * @see Combination#evalGroovyExpression(AxisList,String)
+-     */
+-    public static final class BooleanCategory {
+-        /**
+-         * x -> y
+-         */
+-        public static Boolean implies(Boolean lhs, Boolean rhs) {
+-            return !lhs || rhs;
+-        }
+-    }
+ }
+diff --git a/src/main/java/hudson/matrix/FilterScript.java b/src/main/java/hudson/matrix/FilterScript.java
+index f43cfcd..564fe49 100644
+--- a/src/main/java/hudson/matrix/FilterScript.java
++++ b/src/main/java/hudson/matrix/FilterScript.java
+@@ -3,14 +3,23 @@ package hudson.matrix;
+ import groovy.lang.Binding;
+ import groovy.lang.GroovyShell;
+ import groovy.lang.Script;
++import hudson.Extension;
+ import hudson.Util;
+-import hudson.matrix.Combination.BooleanCategory;
+ import hudson.matrix.MatrixBuild.MatrixBuildExecution;
+ import hudson.model.ParameterValue;
+ import hudson.model.ParametersAction;
+ 
++import java.io.IOException;
+ import java.util.Map;
+ 
++import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
++import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist;
++import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox;
++import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist;
++import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.StaticWhitelist;
++import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext;
++import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
++
+ import static java.lang.Boolean.*;
+ 
+ /**
+@@ -31,9 +40,13 @@ class FilterScript {
+      * @param context
+      *      Variables the script will see.
+      */
+-    boolean evaluate(Binding context) {
++    private boolean evaluate(Binding context) {
+         script.setBinding(context);
+-        return TRUE.equals(script.run());
++        try {
++            return TRUE.equals(GroovySandbox.run(script, Whitelist.all()));
++        } catch (RejectedAccessException x) {
++            throw ScriptApproval.get().accessRejected(x, ApprovalContext.create());
++        }
+     }
+ 
+     /**
+@@ -59,7 +72,7 @@ class FilterScript {
+     /**
+      * Applies the filter to the specified combination in the context of {@code context}.
+      */
+-    public boolean apply(MatrixBuildExecution context, Combination combination) {
++    public final boolean apply(MatrixBuildExecution context, Combination combination) {
+         return apply(context.getProject().getAxes(), combination, getConfiguredBinding(context));
+     }
+ 
+@@ -100,25 +113,18 @@ class FilterScript {
+         if (Util.fixEmptyAndTrim(expression)==null)
+             return defaultScript;
+ 
+-        GroovyShell shell = new GroovyShell(FilterScript.class.getClassLoader());
++        GroovyShell shell = new GroovyShell(GroovySandbox.createSecureClassLoader(FilterScript.class.getClassLoader()), new Binding(), GroovySandbox.createSecureCompilerConfiguration());
+ 
+-        return new FilterScript(shell.parse("use("+BooleanCategory.class.getName().replace('$','.')+") {"+expression+"}"));
++        return new FilterScript(shell.parse(expression));
+     }
+ 
+-    private static final Script EMPTY = new Script() {
+-        @Override
+-        public Object run() {
+-            return true;
+-        }
+-    };
+-
+     /**
+      * Constant that always applies to any combination.
+      * @since 1.541
+      */
+-    /*package*/ static final FilterScript ACCEPT_ALL = new FilterScript(EMPTY) {
++    /*package*/ static final FilterScript ACCEPT_ALL = new FilterScript(null) {
+         @Override
+-        public boolean apply(MatrixBuildExecution context, Combination combination) {
++        public boolean apply(AxisList axes, Combination combination, Binding binding) {
+             return true;
+         }
+     };
+@@ -127,10 +133,18 @@ class FilterScript {
+      * Constant that does not apply to any combination.
+      * @since 1.541
+      */
+-    /*package*/ static final FilterScript REJECT_ALL = new FilterScript(EMPTY) {
++    /*package*/ static final FilterScript REJECT_ALL = new FilterScript(null) {
+         @Override
+-        public boolean apply(MatrixBuildExecution context, Combination combination) {
++        public boolean apply(AxisList axes, Combination combination, Binding binding) {
+             return false;
+         }
+     };
++
++    // TODO JENKINS-25804: harmless generic methods like this should be whitelisted in script-security
++    @Extension
++    public static class ImpliesWhitelist extends ProxyWhitelist {
++        public ImpliesWhitelist() throws IOException {
++            super(new StaticWhitelist("staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods implies java.lang.Boolean java.lang.Boolean"));
++        }
++    }
+ }
+diff --git a/src/test/java/hudson/matrix/CombinationFilterUsingBuildParamsTest.java b/src/test/java/hudson/matrix/CombinationFilterUsingBuildParamsTest.java
+index a302c7e..15b5de1 100644
+--- a/src/test/java/hudson/matrix/CombinationFilterUsingBuildParamsTest.java
++++ b/src/test/java/hudson/matrix/CombinationFilterUsingBuildParamsTest.java
+@@ -53,6 +53,8 @@ import java.util.Map;
+ import jenkins.model.Jenkins;
+ 
+ import org.apache.commons.io.output.ByteArrayOutputStream;
++import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist;
++import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.BlanketWhitelist;
+ import org.junit.Before;
+ import org.junit.Test;
+ import org.junit.runner.RunWith;
+@@ -70,7 +72,8 @@ import org.powermock.modules.junit4.PowerMockRunner;
+  * @author ogondza
+  */
+ @RunWith(PowerMockRunner.class)
+- at PrepareForTest( {Jenkins.class, MatrixBuildListener.class, MatrixProject.class, AbstractItem.class})
++
++ at PrepareForTest({Jenkins.class, MatrixBuildListener.class, MatrixProject.class, AbstractItem.class, Whitelist.class})
+ public class CombinationFilterUsingBuildParamsTest {
+ 
+     /**
+@@ -239,6 +242,8 @@ public class CombinationFilterUsingBuildParamsTest {
+         PowerMockito.mockStatic(Jenkins.class);
+         when(Jenkins.getInstance()).thenReturn(jenkins);
+         when(jenkins.getNodes()).thenReturn(new ArrayList<Node>());
++        PowerMockito.mockStatic(Whitelist.class);
++        when(Whitelist.all()).thenReturn(new BlanketWhitelist());
+     }
+ 
+     private void usingNoListeners() {
+diff --git a/src/test/java/hudson/matrix/CombinationTest.java b/src/test/java/hudson/matrix/CombinationTest.java
+index 9ee7c60..d2fb555 100644
+--- a/src/test/java/hudson/matrix/CombinationTest.java
++++ b/src/test/java/hudson/matrix/CombinationTest.java
+@@ -23,15 +23,15 @@
+  */
+ package hudson.matrix;
+ 
+-import junit.framework.TestCase;
+-
+ import java.util.Map;
+ import java.util.HashMap;
+ 
++import org.jvnet.hudson.test.HudsonTestCase;
++
+ /**
+  * @author Kohsuke Kawaguchi
+  */
+-public class CombinationTest extends TestCase {
++public class CombinationTest extends HudsonTestCase {
+     AxisList axes = new AxisList(
+             new Axis("a","X","x"),
+             new Axis("b","Y","y"));
+diff --git a/src/test/java/hudson/matrix/MatrixTest.java b/src/test/java/hudson/matrix/MatrixTest.java
+index 369898c..c26bf5a 100644
+--- a/src/test/java/hudson/matrix/MatrixTest.java
++++ b/src/test/java/hudson/matrix/MatrixTest.java
+@@ -23,12 +23,21 @@
+  */
+ package hudson.matrix;
+ 
++import hudson.Functions;
+ import hudson.model.Item;
+ import hudson.security.AuthorizationMatrixProperty;
+ import hudson.security.ProjectMatrixAuthorizationStrategy;
++
++import java.io.IOException;
+ import java.util.Collections;
++import java.util.Set;
++
+ import org.acegisecurity.context.SecurityContextHolder;
++
+ import com.gargoylesoftware.htmlunit.xml.XmlPage;
++
++import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
++import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
+ import org.jvnet.hudson.test.HudsonTestCase;
+ import org.jvnet.hudson.test.Bug;
+ 
+@@ -73,4 +82,32 @@ public class MatrixTest extends HudsonTestCase {
+         XmlPage xml = new WebClient().goToXml(project.getUrl() + "api/xml");
+         assertEquals(4, xml.getByXPath("//matrixProject/activeConfiguration").size());
+     }
++
++    // @Issue("SECURITY-125")
++    public void testCombinationFilterSecurity() throws Exception {
++        MatrixProject project = createMatrixProject();
++        String combinationFilter = "jenkins.model.Jenkins.getInstance().setSystemMessage('hacked')";
++        expectRejection(project, combinationFilter, "staticMethod jenkins.model.Jenkins getInstance");
++        assertNull(jenkins.getSystemMessage());
++        expectRejection(project, combinationFilter, "method jenkins.model.Jenkins setSystemMessage java.lang.String");
++        assertNull(jenkins.getSystemMessage());
++        project.setCombinationFilter(combinationFilter);
++        assertEquals("you asked for it", "hacked", jenkins.getSystemMessage());
++    }
++
++    private static void expectRejection(MatrixProject project, String combinationFilter, String signature)
++            throws IOException {
++        ScriptApproval scriptApproval = ScriptApproval.get();
++        assertEquals(Collections.emptySet(), scriptApproval.getPendingSignatures());
++        try {
++            project.setCombinationFilter(combinationFilter);
++        } catch (RejectedAccessException x) {
++            assertEquals(Functions.printThrowable(x), signature, x.getSignature());
++        }
++        Set<ScriptApproval.PendingSignature> pendingSignatures = scriptApproval.getPendingSignatures();
++        assertEquals(1, pendingSignatures.size());
++        assertEquals(signature, pendingSignatures.iterator().next().signature);
++        scriptApproval.approveSignature(signature);
++        assertEquals(Collections.emptySet(), scriptApproval.getPendingSignatures());
++    }
+ }
+-- 
+2.1.0
+
diff --git a/jenkins-matrix-project-plugin.spec b/jenkins-matrix-project-plugin.spec
index 922e2fc..09b1328 100644
--- a/jenkins-matrix-project-plugin.spec
+++ b/jenkins-matrix-project-plugin.spec
@@ -4,7 +4,7 @@
 
 Name:           jenkins-%{mod_name}
 Version:        1.4
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        Jenkins Matrix Project Plugin
 
 # License is specified in pom.xml
@@ -14,6 +14,8 @@ Source0:        https://github.com/jenkinsci/%{mod_name}/archive/%{short_name}-%
 # Text copied from http://www.opensource.org/licenses/mit-license.php
 Source1:        LICENSE.txt
 
+Patch0:         0001-Fix-SECURITY-125.patch
+
 BuildRequires:  maven-local
 BuildRequires:  mvn(org.jenkins-ci.plugins:plugin:pom:)
 BuildRequires:  mvn(org.kohsuke:access-modifier-checker)
@@ -36,6 +38,8 @@ This package contains the API documentation for %{name}.
 %prep
 %setup -q -n %{mod_name}-%{short_name}-%{version}
 
+%patch0 -p1
+
 cp %{SOURCE1} .
 %mvn_package ::hpi: __noinstall
 %mvn_file ::jar:: %{name}/%{short_name} %{plugin_home}/WEB-INF/lib/%{short_name}
@@ -67,6 +71,10 @@ sed -i 's|%{plugin_home}/WEB-INF/lib/%{short_name}.jar||' .mfiles
 %doc LICENSE.txt
 
 %changelog
+* Sun Mar 29 2015 Michal Srb <msrb at redhat.com> - 1.4-2
+- Fix SECURITY-125
+- Resolves: CVE-2015-1806
+
 * Fri Nov 21 2014 Michal Srb <msrb at redhat.com> - 1.4-1
 - Update to upstream version 1.4
 
-- 
cgit v0.10.2


	http://pkgs.fedoraproject.org/cgit/jenkins-matrix-project-plugin.git/commit/?h=f21&id=7c978515519cbaf49b7c26b65f48bfe7be97d6bd


More information about the scm-commits mailing list