This is an automated email from the ASF dual-hosted git repository. jbonofre pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/activemq.git
The following commit(s) were added to refs/heads/master by this push: new a73a85e AMQ-7438 - Harden deserialization new 1f914bb Merge pull request #502 from coheigea/AMQ-7438 a73a85e is described below commit a73a85e6c21ac2905feb162d9132993b231f391b Author: Colm O hEigeartaigh <cohei...@apache.org> AuthorDate: Fri Mar 6 17:22:07 2020 +0000 AMQ-7438 - Harden deserialization --- .../plugin/SubQueueSelectorCacheBroker.java | 20 +++++++- .../activemq/store/kahadb/MessageDatabase.java | 25 ++++++++-- .../store/kahadb/disk/util/ObjectMarshaller.java | 57 ---------------------- 3 files changed, 41 insertions(+), 61 deletions(-) diff --git a/activemq-broker/src/main/java/org/apache/activemq/plugin/SubQueueSelectorCacheBroker.java b/activemq-broker/src/main/java/org/apache/activemq/plugin/SubQueueSelectorCacheBroker.java index ecea02f..6147f4c 100644 --- a/activemq-broker/src/main/java/org/apache/activemq/plugin/SubQueueSelectorCacheBroker.java +++ b/activemq-broker/src/main/java/org/apache/activemq/plugin/SubQueueSelectorCacheBroker.java @@ -20,8 +20,11 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -192,7 +195,7 @@ public class SubQueueSelectorCacheBroker extends BrokerFilter implements Runnabl if (persistFile != null && persistFile.exists()) { try { try (FileInputStream fis = new FileInputStream(persistFile);) { - ObjectInputStream in = new ObjectInputStream(fis); + ObjectInputStream in = new SubSelectorClassObjectInputStream(fis); try { LOG.debug("Reading selector cache...."); subSelectorCache = (ConcurrentHashMap<String, Set<String>>) in.readObject(); @@ -365,4 +368,19 @@ public class SubQueueSelectorCacheBroker extends BrokerFilter implements Runnabl return false; } } + + private static class SubSelectorClassObjectInputStream extends ObjectInputStream { + + public SubSelectorClassObjectInputStream(InputStream is) throws IOException { + super(is); + } + + @Override + protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + if (!(desc.getName().equals("java.lang.String") || desc.getName().startsWith("java.util."))) { + throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName()); + } + return super.resolveClass(desc); + } + } } diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java index d12c7d9..5c38435 100644 --- a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java +++ b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/MessageDatabase.java @@ -27,8 +27,10 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; +import java.io.InvalidClassException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; @@ -805,7 +807,7 @@ public abstract class MessageDatabase extends ServiceSupport implements BrokerSe if (metadata.producerSequenceIdTrackerLocation != null) { try { KahaProducerAuditCommand audit = (KahaProducerAuditCommand) load(metadata.producerSequenceIdTrackerLocation); - ObjectInputStream objectIn = new ObjectInputStream(audit.getAudit().newInput()); + ObjectInputStream objectIn = new MessageDatabaseObjectInputStream(audit.getAudit().newInput()); int maxNumProducers = getMaxFailoverProducersToTrack(); int maxAuditDepth = getFailoverProducersAuditDepth(); metadata.producerSequenceIdTracker = (ActiveMQMessageAuditNoSync) objectIn.readObject(); @@ -826,7 +828,7 @@ public abstract class MessageDatabase extends ServiceSupport implements BrokerSe if (metadata.ackMessageFileMapLocation != null) { try { KahaAckMessageFileMapCommand audit = (KahaAckMessageFileMapCommand) load(metadata.ackMessageFileMapLocation); - ObjectInputStream objectIn = new ObjectInputStream(audit.getAckMessageFileMap().newInput()); + ObjectInputStream objectIn = new MessageDatabaseObjectInputStream(audit.getAckMessageFileMap().newInput()); metadata.ackMessageFileMap = (Map<Integer, Set<Integer>>) objectIn.readObject(); metadata.ackMessageFileMapDirtyFlag.lazySet(true); requiresReplay = false; @@ -4114,7 +4116,7 @@ public abstract class MessageDatabase extends ServiceSupport implements BrokerSe byte[] data = new byte[dataLen]; dataIn.readFully(data); ByteArrayInputStream bais = new ByteArrayInputStream(data); - ObjectInputStream oin = new ObjectInputStream(bais); + ObjectInputStream oin = new MessageDatabaseObjectInputStream(bais); try { return (HashSet<String>) oin.readObject(); } catch (ClassNotFoundException cfe) { @@ -4227,4 +4229,21 @@ public abstract class MessageDatabase extends ServiceSupport implements BrokerSe public void setEnableSubscriptionStatistics(boolean enableSubscriptionStatistics) { this.enableSubscriptionStatistics = enableSubscriptionStatistics; } + + private static class MessageDatabaseObjectInputStream extends ObjectInputStream { + + public MessageDatabaseObjectInputStream(InputStream is) throws IOException { + super(is); + } + + @Override + protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + if (!(desc.getName().startsWith("java.lang.") || desc.getName().startsWith("java.util.") + || desc.getName().startsWith("org.apache.activemq."))) { + throw new InvalidClassException("Unauthorized deserialization attempt", desc.getName()); + } + return super.resolveClass(desc); + } + + } } diff --git a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/util/ObjectMarshaller.java b/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/util/ObjectMarshaller.java deleted file mode 100644 index 585ec52..0000000 --- a/activemq-kahadb-store/src/main/java/org/apache/activemq/store/kahadb/disk/util/ObjectMarshaller.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * 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.store.kahadb.disk.util; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInput; -import java.io.DataOutput; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -/** - * Implementation of a Marshaller for Objects - * - * - */ -public class ObjectMarshaller extends VariableMarshaller<Object> { - - public void writePayload(Object object, DataOutput dataOut) throws IOException { - ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); - ObjectOutputStream objectOut = new ObjectOutputStream(bytesOut); - objectOut.writeObject(object); - objectOut.close(); - byte[] data = bytesOut.toByteArray(); - dataOut.writeInt(data.length); - dataOut.write(data); - } - - public Object readPayload(DataInput dataIn) throws IOException { - int size = dataIn.readInt(); - byte[] data = new byte[size]; - dataIn.readFully(data); - ByteArrayInputStream bytesIn = new ByteArrayInputStream(data); - ObjectInputStream objectIn = new ObjectInputStream(bytesIn); - try { - return objectIn.readObject(); - } catch (ClassNotFoundException e) { - throw new IOException(e.getMessage()); - } - } - -}