Hello security team, I have prepared a security update for ActiveMQ regarding CVE-2015-5254. Please find attached the proposed debdiff for Jessie.
Unfortunately this patch relies on classes in libxstream-java that are not present in Wheezy. We could backport the Jessie version of libxstream-java to Wheezy but before I need to do some tests with its reverse-dependencies. Regards, Markus
diff -Nru activemq-5.6.0+dfsg1/debian/changelog activemq-5.6.0+dfsg1/debian/changelog --- activemq-5.6.0+dfsg1/debian/changelog 2015-08-03 21:30:49.000000000 +0200 +++ activemq-5.6.0+dfsg1/debian/changelog 2016-03-16 21:20:06.000000000 +0100 @@ -1,3 +1,14 @@ +activemq (5.6.0+dfsg1-4+deb8u2) jessie-security; urgency=high + + * Team upload. + * Fix CVE-2015-5254: + Apache ActiveMQ 5.x before 5.13.0 does not restrict the classes that can be + serialized in the broker, which allows remote attackers to execute + arbitrary code via a crafted serialized Java Message Service (JMS) + ObjectMessage object. + + -- Markus Koschany <a...@debian.org> Wed, 16 Mar 2016 19:30:17 +0100 + activemq (5.6.0+dfsg1-4+deb8u1) jessie-security; urgency=high * Team upload. diff -Nru activemq-5.6.0+dfsg1/debian/patches/CVE-2015-5254.patch activemq-5.6.0+dfsg1/debian/patches/CVE-2015-5254.patch --- activemq-5.6.0+dfsg1/debian/patches/CVE-2015-5254.patch 1970-01-01 01:00:00.000000000 +0100 +++ activemq-5.6.0+dfsg1/debian/patches/CVE-2015-5254.patch 2016-03-16 21:20:06.000000000 +0100 @@ -0,0 +1,253 @@ +From: Markus Koschany <a...@debian.org> +Date: Wed, 16 Mar 2016 19:26:46 +0100 +Subject: CVE-2015-5254 + +Apache ActiveMQ 5.x before 5.13.0 does not restrict the classes that can be +serialized in the broker, which allows remote attackers to execute arbitrary +code via a crafted serialized Java Message Service (JMS) ObjectMessage object. + +Origin: https://git-wip-us.apache.org/repos/asf?p=activemq.git;h=6f03921b31d9fefeddb0f4fa63150ed1f94a14b1 +Origin: https://git-wip-us.apache.org/repos/asf?p=activemq.git;h=73a0caf758f9e4916783a205c7e422b4db27905c +Origin: http://pkgs.fedoraproject.org/cgit/activemq.git/diff/activemq-5.6.0-CVE-2015-5254.patch?id=e3ef8a1b62d10273a814090be9168aa3019ace72 +Debian-Bug: https://bugs.debian.org/809733 +--- + .../transport/stomp/JmsFrameTranslator.java | 5 ++- + .../activemq/transport/stomp/XStreamSupport.java | 47 +++++++++++++++++++++ + .../util/ClassLoadingAwareObjectInputStream.java | 48 ++++++++++++++++++++-- + .../transport/xstream/XStreamWireFormat.java | 29 ++++++++++++- + .../java/org/apache/activemq/web/MessageQuery.java | 4 +- + 5 files changed, 124 insertions(+), 9 deletions(-) + create mode 100644 activemq-core/src/main/java/org/apache/activemq/transport/stomp/XStreamSupport.java + +diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/JmsFrameTranslator.java b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/JmsFrameTranslator.java +index 5274b34..4fd18b0 100644 +--- a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/JmsFrameTranslator.java ++++ b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/JmsFrameTranslator.java +@@ -84,7 +84,7 @@ public class JmsFrameTranslator extends LegacyFrameTranslator implements + msg = createMapMessage(in); + break; + default: +- throw new Exception("Unkown transformation: " + transformation); ++ throw new Exception("Unknown transformation: " + transformation); + } + } catch (Throwable e) { + command.getHeaders().put(Stomp.Headers.TRANSFORMATION_ERROR, e.getMessage()); +@@ -243,7 +243,8 @@ public class JmsFrameTranslator extends LegacyFrameTranslator implements + } + + if (xstream == null) { +- xstream = new XStream(); ++ xstream = XStreamSupport.createXStream(); ++ xstream.ignoreUnknownElements(); + } + return xstream; + +diff --git a/activemq-core/src/main/java/org/apache/activemq/transport/stomp/XStreamSupport.java b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/XStreamSupport.java +new file mode 100644 +index 0000000..abcca72 +--- /dev/null ++++ b/activemq-core/src/main/java/org/apache/activemq/transport/stomp/XStreamSupport.java +@@ -0,0 +1,47 @@ ++/** ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * The ASF licenses this file to You under the Apache License, Version 2.0 ++ * (the "License"); you may not use this file except in compliance with ++ * the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++package org.apache.activemq.transport.stomp; ++ ++import com.thoughtworks.xstream.XStream; ++import com.thoughtworks.xstream.security.AnyTypePermission; ++import com.thoughtworks.xstream.security.NoTypePermission; ++import com.thoughtworks.xstream.security.PrimitiveTypePermission; ++import org.apache.activemq.util.ClassLoadingAwareObjectInputStream; ++ ++import java.util.Collection; ++import java.util.Map; ++ ++public class XStreamSupport { ++ ++ public static XStream createXStream() { ++ XStream stream = new XStream(); ++ stream.addPermission(NoTypePermission.NONE); ++ stream.addPermission(PrimitiveTypePermission.PRIMITIVES); ++ stream.allowTypeHierarchy(Collection.class); ++ stream.allowTypeHierarchy(Map.class); ++ stream.allowTypes(new Class[]{String.class}); ++ if (ClassLoadingAwareObjectInputStream.isAllAllowed()) { ++ stream.addPermission(AnyTypePermission.ANY); ++ } else { ++ for (String packageName : ClassLoadingAwareObjectInputStream.serializablePackages) { ++ stream.allowTypesByWildcard(new String[]{packageName + ".**"}); ++ } ++ } ++ return stream; ++ } ++ ++} +diff --git a/activemq-core/src/main/java/org/apache/activemq/util/ClassLoadingAwareObjectInputStream.java b/activemq-core/src/main/java/org/apache/activemq/util/ClassLoadingAwareObjectInputStream.java +index 82da30c..6a2864f 100644 +--- a/activemq-core/src/main/java/org/apache/activemq/util/ClassLoadingAwareObjectInputStream.java ++++ b/activemq-core/src/main/java/org/apache/activemq/util/ClassLoadingAwareObjectInputStream.java +@@ -21,7 +21,10 @@ import java.io.InputStream; + import java.io.ObjectInputStream; + import java.io.ObjectStreamClass; + import java.lang.reflect.Proxy; ++import java.util.Arrays; ++import java.util.Collection; + import java.util.HashMap; ++import java.util.Map; + + @SuppressWarnings("rawtypes") + public class ClassLoadingAwareObjectInputStream extends ObjectInputStream { +@@ -29,6 +32,12 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream { + private static final ClassLoader FALLBACK_CLASS_LOADER = + ClassLoadingAwareObjectInputStream.class.getClassLoader(); + ++ public static final String[] serializablePackages; ++ ++ static { ++ serializablePackages = System.getProperty("org.apache.activemq.SERIALIZABLE_PACKAGES", "java.lang,java.util,org.apache.activemq,org.fusesource.hawtbuf,com.thoughtworks.xstream.mapper").split(","); ++ } ++ + /** + * Maps primitive type names to corresponding class objects. + */ +@@ -40,7 +49,9 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream { + + protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); +- return load(classDesc.getName(), cl); ++ Class clazz = load(classDesc.getName(), cl); ++ checkSecurity(clazz); ++ return clazz; + } + + protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { +@@ -50,18 +61,47 @@ public class ClassLoadingAwareObjectInputStream extends ObjectInputStream { + cinterfaces[i] = load(interfaces[i], cl); + } + ++ Class clazz = null; + try { +- return Proxy.getProxyClass(cl, cinterfaces); ++ clazz = Proxy.getProxyClass(cl, cinterfaces); + } catch (IllegalArgumentException e) { + try { +- return Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces); ++ clazz = Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces); + } catch (IllegalArgumentException e1) { + } + +- throw new ClassNotFoundException(null, e); ++ } ++ ++ if (clazz != null) { ++ checkSecurity(clazz); ++ return clazz; ++ } else { ++ throw new ClassNotFoundException(null); + } + } + ++ public static boolean isAllAllowed() { ++ return serializablePackages.length == 1 && serializablePackages[0].equals("*"); ++ } ++ ++ private void checkSecurity(Class clazz) throws ClassNotFoundException { ++ if (!clazz.isPrimitive()) { ++ if (clazz.getPackage() != null && !isAllAllowed()) { ++ boolean found = false; ++ for (String packageName : serializablePackages) { ++ if (clazz.getPackage().getName().equals(packageName) || clazz.getPackage().getName().startsWith(packageName + ".")) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (!found) { ++ throw new ClassNotFoundException("Forbidden " + clazz + "! This class is not allowed to be serialized. Add package with 'org.apache.activemq.SERIALIZABLE_PACKAGES' system property."); ++ } ++ } ++ } ++ } ++ + private Class<?> load(String className, ClassLoader cl) throws ClassNotFoundException { + try { + return Class.forName(className, false, cl); +diff --git a/activemq-optional/src/main/java/org/apache/activemq/transport/xstream/XStreamWireFormat.java b/activemq-optional/src/main/java/org/apache/activemq/transport/xstream/XStreamWireFormat.java +index 91ae036..1b83e2e 100755 +--- a/activemq-optional/src/main/java/org/apache/activemq/transport/xstream/XStreamWireFormat.java ++++ b/activemq-optional/src/main/java/org/apache/activemq/transport/xstream/XStreamWireFormat.java +@@ -17,9 +17,15 @@ + package org.apache.activemq.transport.xstream; + + import com.thoughtworks.xstream.XStream; ++import com.thoughtworks.xstream.converters.Converter; ++import com.thoughtworks.xstream.converters.MarshallingContext; ++import com.thoughtworks.xstream.converters.UnmarshallingContext; ++import com.thoughtworks.xstream.io.HierarchicalStreamReader; ++import com.thoughtworks.xstream.io.HierarchicalStreamWriter; + import org.apache.activemq.command.Command; + import org.apache.activemq.command.MarshallAware; + import org.apache.activemq.command.MessageDispatch; ++import org.apache.activemq.transport.stomp.XStreamSupport; + import org.apache.activemq.transport.util.TextWireFormat; + import org.apache.activemq.wireformat.WireFormat; + +@@ -105,7 +111,28 @@ public class XStreamWireFormat extends TextWireFormat { + // Implementation methods + // ------------------------------------------------------------------------- + protected XStream createXStream() { +- return new XStream(); ++ final XStream xstream = XStreamSupport.createXStream(); ++ xstream.ignoreUnknownElements(); ++ xstream.registerConverter(new Converter() { ++ final Converter delegate = xstream.getConverterLookup().lookupConverterForType(ByteSequence.class); ++ @Override ++ public void marshal(Object o, HierarchicalStreamWriter hierarchicalStreamWriter, MarshallingContext marshallingContext) { ++ ByteSequence byteSequence = (ByteSequence)o; ++ byteSequence.compact(); ++ delegate.marshal(byteSequence, hierarchicalStreamWriter, marshallingContext); ++ } ++ ++ @Override ++ public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext unmarshallingContext) { ++ return delegate.unmarshal(hierarchicalStreamReader, unmarshallingContext); ++ } ++ ++ @Override ++ public boolean canConvert(Class aClass) { ++ return aClass == ByteSequence.class; ++ } ++ }); ++ return xstream; + } + + } +diff --git a/activemq-web/src/main/java/org/apache/activemq/web/MessageQuery.java b/activemq-web/src/main/java/org/apache/activemq/web/MessageQuery.java +index 1d0ec06..a6cbd51 100644 +--- a/activemq-web/src/main/java/org/apache/activemq/web/MessageQuery.java ++++ b/activemq-web/src/main/java/org/apache/activemq/web/MessageQuery.java +@@ -80,9 +80,9 @@ public class MessageQuery extends QueueBrowseQuery { + if (message instanceof ObjectMessage) { + try { + return ((ObjectMessage) message).getObject(); +- } catch (JMSException e) { ++ } catch (Exception e) { + //message could not be parsed, make the reason available +- return e; ++ return new String("Cannot display ObjectMessage body. Reason: " + e.getMessage()); + } + } + if (message instanceof MapMessage) { diff -Nru activemq-5.6.0+dfsg1/debian/patches/series activemq-5.6.0+dfsg1/debian/patches/series --- activemq-5.6.0+dfsg1/debian/patches/series 2015-08-03 15:08:47.000000000 +0200 +++ activemq-5.6.0+dfsg1/debian/patches/series 2016-03-16 21:20:06.000000000 +0100 @@ -10,3 +10,4 @@ CVE-2014-3600.patch CVE-2014-3612.patch CVE-2014-3576.patch +CVE-2015-5254.patch
signature.asc
Description: OpenPGP digital signature