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 <apo@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 <apo@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
Attachment:
signature.asc
Description: OpenPGP digital signature