You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2018/01/23 13:29:52 UTC
[5/5] ignite git commit: ignite-6643 Marshalling improvements
ignite-6643 Marshalling improvements
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/ca877b43
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/ca877b43
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/ca877b43
Branch: refs/heads/ignite-6643
Commit: ca877b4346f5099beb563b9915a89627a8f4f2f3
Parents: 5216ac5
Author: Andrey Gura <ag...@apache.org>
Authored: Mon Jan 22 22:41:54 2018 +0300
Committer: Andrey Gura <ag...@apache.org>
Committed: Tue Jan 23 16:25:52 2018 +0300
----------------------------------------------------------------------
.../apache/ignite/IgniteSystemProperties.java | 60 +----
.../org/apache/ignite/internal/ClassSet.java | 108 +++++++++
.../ignite/internal/GridKernalContext.java | 6 +
.../ignite/internal/GridKernalContextImpl.java | 13 +-
.../apache/ignite/internal/IgniteKernal.java | 107 ++++++++-
.../ignite/internal/MarshallerContextImpl.java | 8 +-
.../wal/reader/StandaloneGridKernalContext.java | 6 +
.../ignite/internal/util/IgniteUtils.java | 15 ++
.../ignite/marshaller/MarshallerUtils.java | 6 +
.../ignite/marshaller/jdk/JdkMarshaller.java | 20 +-
.../jdk/JdkMarshallerObjectInputStream.java | 9 +-
.../spi/discovery/tcp/TcpDiscoverySpi.java | 8 +-
.../org/apache/ignite/stream/StreamAdapter.java | 2 +-
.../ignite/stream/socket/SocketStreamer.java | 8 +-
.../test/config/class_list_exploit_excluded.txt | 18 ++
.../test/config/class_list_exploit_included.txt | 19 ++
.../apache/ignite/internal/ClassSetTest.java | 71 ++++++
.../DiscoveryUnmarshalVulnerabilityTest.java | 180 +++++++++++++++
...ocketStreamerUnmarshalVulnerabilityTest.java | 222 +++++++++++++++++++
.../junits/GridTestKernalContext.java | 9 +-
.../ignite/testsuites/IgniteBasicTestSuite.java | 3 +
.../IgniteSpiDiscoverySelfTestSuite.java | 3 +
.../testsuites/IgniteStreamSelfTestSuite.java | 2 +
23 files changed, 834 insertions(+), 69 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
index 9cd031d..7761292 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java
@@ -28,7 +28,6 @@ import org.apache.ignite.cluster.ClusterGroup;
import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.internal.client.GridClient;
import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
-import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.stream.StreamTransformer;
import org.jetbrains.annotations.Nullable;
@@ -222,11 +221,6 @@ public final class IgniteSystemProperties {
public static final String IGNITE_MAX_COMPLETED_TX_COUNT = "IGNITE_MAX_COMPLETED_TX_COUNT";
/**
- * Concurrency level for all concurrent hash maps created by Ignite.
- */
- public static final String IGNITE_MAP_CONCURRENCY_LEVEL = "IGNITE_MAP_CONCURRENCY_LEVEL";
-
- /**
* Transactions that take more time, than value of this property, will be output to log
* with warning level. {@code 0} (default value) disables warning on slow transactions.
*/
@@ -320,13 +314,6 @@ public final class IgniteSystemProperties {
/** Ttl of removed cache entries (ms). */
public static final String IGNITE_CACHE_REMOVED_ENTRIES_TTL = "IGNITE_CACHE_REMOVED_ENTRIES_TTL";
- /** Maximum amount of concurrent updates per system thread in atomic caches in case of PRIMARY_SYNC or FULL_ASYNC
- * write synchronization mode. If this limit is exceeded then update will be performed with FULL_SYNC
- * synchronization mode. If value is {@code 0} then limit is unbounded.
- */
- public static final String IGNITE_ATOMIC_CACHE_MAX_CONCURRENT_DHT_UPDATES =
- "IGNITE_ATOMIC_CACHE_MAX_CONCURRENT_DHT_UPDATES";
-
/**
* Comma separated list of addresses in format "10.100.22.100:45000,10.100.22.101:45000".
* Makes sense only for {@link org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder}.
@@ -479,9 +466,6 @@ public final class IgniteSystemProperties {
/** Number of cache operation retries in case of topology exceptions. */
public static final String IGNITE_CACHE_RETRIES_COUNT = "IGNITE_CACHE_RETRIES_COUNT";
- /** Number of times pending cache objects will be dumped to the log in case of partition exchange timeout. */
- public static final String IGNITE_DUMP_PENDING_OBJECTS_THRESHOLD = "IGNITE_DUMP_PENDING_OBJECTS_THRESHOLD";
-
/** If this property is set to {@code true} then Ignite will log thread dump in case of partition exchange timeout. */
public static final String IGNITE_THREAD_DUMP_ON_EXCHANGE_TIMEOUT = "IGNITE_THREAD_DUMP_ON_EXCHANGE_TIMEOUT";
@@ -524,6 +508,12 @@ public final class IgniteSystemProperties {
public static final String IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2 =
"IGNITE_BINARY_MARSHALLER_USE_STRING_SERIALIZATION_VER_2";
+ /** Defines path to the file that contains list of classes allowed to safe deserialization.*/
+ public static final String IGNITE_MARSHALLER_WHITELIST = "IGNITE_MARSHALLER_WHITELIST";
+
+ /** Defines path to the file that contains list of classes disallowed to safe deserialization.*/
+ public static final String IGNITE_MARSHALLER_BLACKLIST = "IGNITE_MARSHALLER_BLACKLIST";
+
/**
* If set to {@code true}, then default selected keys set is used inside
* {@code GridNioServer} which lead to some extra garbage generation when
@@ -689,16 +679,7 @@ public final class IgniteSystemProperties {
*/
public static final String IGNITE_FORCE_START_JAVA7 = "IGNITE_FORCE_START_JAVA7";
- /** Returns true for system properties only avoiding sending sensitive information. */
- private static final IgnitePredicate<Map.Entry<String, String>> PROPS_FILTER = new IgnitePredicate<Map.Entry<String, String>>() {
- @Override public boolean apply(final Map.Entry<String, String> entry) {
- final String key = entry.getKey();
-
- return key.startsWith("java.") || key.startsWith("os.") || key.startsWith("user.");
- }
- };
-
- /**
+ /**
* When set to {@code true}, Ignite switches to compatibility mode with versions that don't
* support service security permissions. In this case security permissions will be ignored
* (if they set).
@@ -740,11 +721,6 @@ public final class IgniteSystemProperties {
public static final String IGNITE_ENABLE_FORCIBLE_NODE_KILL = "IGNITE_ENABLE_FORCIBLE_NODE_KILL";
/**
- *
- */
- public static final String IGNITE_WAL_ARCHIVE_COMPACT_SKIP_DELTA_RECORD = "IGNITE_WAL_ARCHIVE_COMPACT_SKIP_DELTA_RECORD";
-
- /**
* Tasks stealing will be started if tasks queue size per data-streamer thread exceeds this threshold.
* <p>
* Default value is {@code 4}.
@@ -1023,26 +999,4 @@ public final class IgniteSystemProperties {
return sysProps;
}
-
- /**
- * Does the same as {@link #snapshot()} but filters out
- * possible sensitive user data.
- *
- * @return Snapshot of system properties.
- */
- @SuppressWarnings("unchecked")
- public static Properties safeSnapshot() {
- final Properties props = snapshot();
-
- final Iterator<Map.Entry<Object, Object>> iter = props.entrySet().iterator();
-
- while (iter.hasNext()) {
- final Map.Entry entry = iter.next();
-
- if (!PROPS_FILTER.apply(entry))
- iter.remove();
- }
-
- return props;
- }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/internal/ClassSet.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/ClassSet.java b/modules/core/src/main/java/org/apache/ignite/internal/ClassSet.java
new file mode 100644
index 0000000..400984d
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/ClassSet.java
@@ -0,0 +1,108 @@
+/*
+ * 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.ignite.internal;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.IllegalFormatException;
+import java.util.Map;
+
+/**
+ * Set of classes represented as prefix tree.
+ * {@code *} symbol is allowed and indicates that all packages and classes are included.
+ */
+public class ClassSet {
+ /** Corresponds to {@code *} symbol. */
+ private static final Map<String, Node> ALL = Collections.emptyMap();
+
+ /** Root. */
+ private Node root = new Node();
+
+ /**
+ * Adds class name to the set.
+ *
+ * @param clsName Class name.
+ */
+ public void add(String clsName) {
+ String[] tokens = clsName.split("\\.");
+
+ Node cur = root;
+
+ for (int i = 0; i < tokens.length; i++) {
+ if (cur.children == ALL)
+ return;
+
+ if (tokens[i].equals("*")) {
+ if (i != tokens.length - 1)
+ throw new IllegalArgumentException("Incorrect class name format.");
+
+ cur.children = ALL;
+
+ return;
+ }
+
+ if (cur.children == null)
+ cur.children = new HashMap<>();
+
+ Node n = cur.children.get(tokens[i]);
+
+ if (n == null) {
+ n = new Node();
+
+ cur.children.put(tokens[i], n);
+ }
+
+ cur = n;
+ }
+ }
+
+ /**
+ * @param clsName Class name.
+ */
+ public boolean contains(String clsName) {
+ String[] tokens = clsName.split("\\.");
+
+ Node cur = root;
+
+ for (int i = 0; i < tokens.length; i++) {
+ if (cur.children == ALL)
+ return true;
+
+ if (cur.children == null)
+ return false;
+
+ Node n = cur.children.get(tokens[i]);
+
+ if (n == null)
+ return false;
+
+ if (i == tokens.length - 1)
+ return true;
+
+ cur = n;
+ }
+
+ return false;
+ }
+
+ /** */
+ private static class Node {
+ /** Children. */
+ private Map<String, Node> children;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
index ce12b61..2877dad 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
@@ -69,6 +69,7 @@ import org.apache.ignite.internal.suggestions.GridPerformanceSuggestions;
import org.apache.ignite.internal.util.IgniteExceptionRegistry;
import org.apache.ignite.internal.util.StripedExecutor;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
+import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.plugin.PluginNotFoundException;
import org.apache.ignite.plugin.PluginProvider;
import org.apache.ignite.thread.IgniteStripedThreadPoolExecutor;
@@ -655,4 +656,9 @@ public interface GridKernalContext extends Iterable<GridComponent> {
* @return subscription processor to manage internal-only (strict node-local) subscriptions between components.
*/
public GridInternalSubscriptionProcessor internalSubscriptionProcessor();
+
+ /**
+ * @return class name filter for marshaller.
+ */
+ public IgnitePredicate<String> classNameFilter();
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
index 36c6231..61d0dd1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
@@ -91,6 +91,7 @@ import org.apache.ignite.internal.util.tostring.GridToStringInclude;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.plugin.PluginNotFoundException;
import org.apache.ignite.plugin.PluginProvider;
import org.apache.ignite.thread.IgniteStripedThreadPoolExecutor;
@@ -385,6 +386,9 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
/** */
private GridInternalSubscriptionProcessor internalSubscriptionProc;
+ /** Class name filter. */
+ private IgnitePredicate<String> clsFilter;
+
/**
* No-arg constructor is required by externalization.
*/
@@ -438,7 +442,8 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
ExecutorService qryExecSvc,
ExecutorService schemaExecSvc,
@Nullable Map<String, ? extends ExecutorService> customExecSvcs,
- List<PluginProvider> plugins
+ List<PluginProvider> plugins,
+ IgnitePredicate<String> clsFilter
) {
assert grid != null;
assert cfg != null;
@@ -463,6 +468,7 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
this.qryExecSvc = qryExecSvc;
this.schemaExecSvc = schemaExecSvc;
this.customExecSvcs = customExecSvcs;
+ this.clsFilter = clsFilter;
marshCtx = new MarshallerContextImpl(plugins);
@@ -1092,6 +1098,11 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
}
/** {@inheritDoc} */
+ @Override public IgnitePredicate<String> classNameFilter() {
+ return clsFilter;
+ }
+
+ /** {@inheritDoc} */
@Override public String toString() {
return S.toString(GridKernalContextImpl.class, this);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 16698b5..3094963 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -17,10 +17,14 @@
package org.apache.ignite.internal;
+import java.io.BufferedReader;
import java.io.Externalizable;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.InvalidObjectException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
@@ -259,6 +263,8 @@ import static org.apache.ignite.internal.IgniteVersionUtils.VER;
import static org.apache.ignite.internal.IgniteVersionUtils.VER_STR;
import static org.apache.ignite.lifecycle.LifecycleEventType.AFTER_NODE_START;
import static org.apache.ignite.lifecycle.LifecycleEventType.BEFORE_NODE_START;
+import static org.apache.ignite.marshaller.MarshallerUtils.CLS_NAMES_FILE;
+import static org.apache.ignite.marshaller.MarshallerUtils.JDK_CLS_NAMES_FILE;
/**
* Ignite kernal.
@@ -834,7 +840,8 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable {
qryExecSvc,
schemaExecSvc,
customExecSvcs,
- plugins
+ plugins,
+ classNameFilter()
);
cfg.getMarshaller().setContext(ctx.marshallerContext());
@@ -1685,6 +1692,104 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable {
}
/**
+ * Returns class name filter for marshaller.
+ * @return Class name filter for marshaller.
+ */
+ private IgnitePredicate<String> classNameFilter() throws IgniteCheckedException {
+ ClassSet whiteList = classWhiteList();
+ ClassSet blackList = classBlackList();
+
+ return new IgnitePredicate<String>() {
+ @Override public boolean apply(String s) {
+ // Allows all primitive arrays and checks arrays' type.
+ if ((blackList != null || whiteList != null) && s.charAt(0) == '[') {
+ if (s.charAt(1) == 'L' && s.length() > 2)
+ s = s.substring(2, s.length() - 1);
+ else
+ return true;
+ }
+
+ return (blackList == null || !blackList.contains(s)) && (whiteList == null || whiteList.contains(s));
+ }
+ };
+ }
+
+ /**
+ * @return White list of classes.
+ */
+ private ClassSet classWhiteList() throws IgniteCheckedException {
+ ClassSet clsSet = null;
+
+ String fileName = IgniteSystemProperties.getString(IgniteSystemProperties.IGNITE_MARSHALLER_WHITELIST);
+
+ if (fileName != null) {
+ clsSet = new ClassSet();
+
+ addClassNames(JDK_CLS_NAMES_FILE, clsSet);
+ addClassNames(CLS_NAMES_FILE, clsSet);
+ addClassNames(fileName, clsSet);
+ }
+
+ return clsSet;
+ }
+
+ /**
+ * @return Black list of classes.
+ */
+ private ClassSet classBlackList() throws IgniteCheckedException {
+ ClassSet clsSet = null;
+
+ String blackListFileName = IgniteSystemProperties.getString(IgniteSystemProperties.IGNITE_MARSHALLER_BLACKLIST);
+
+ if (blackListFileName != null)
+ addClassNames(blackListFileName, clsSet = new ClassSet());
+
+ return clsSet;
+ }
+
+
+ /**
+ * Reads class names from resource referred by given system property name and returns set of classes.
+ * @param fileName File name containing list of classes.
+ * @param clsSet Class set for update.
+ * @return Set of classes.
+ */
+ private void addClassNames(String fileName, ClassSet clsSet) throws IgniteCheckedException {
+ InputStream is = this.getClass().getClassLoader().getResourceAsStream(fileName);
+
+ if (is == null) {
+ try {
+ is = new FileInputStream(new File(fileName));
+ }
+ catch (FileNotFoundException e) {
+ throw new IgniteCheckedException("File " + fileName + " not found.");
+ }
+ }
+
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
+ String line;
+
+ for (int i = 1; (line = reader.readLine()) != null; i++) {
+ String s = line.trim();
+
+ if (!s.isEmpty() && s.charAt(0) != '#' && s.charAt(0) != '[') {
+ try {
+ clsSet.add(s);
+ }
+ catch (IllegalArgumentException e) {
+ throw new IgniteCheckedException("Exception occurred while reading list of classes" +
+ "[path=" + fileName + ", row=" + i + ", line=" + s + ']', e);
+ }
+ }
+ }
+ }
+ catch (IOException e) {
+ throw new IgniteCheckedException("Exception occurred while reading and creating list of classes " +
+ "[path=" + fileName + ']', e);
+ }
+ }
+
+ /**
* Add helper.
*
* @param helper Helper.
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java
index 08661a3..8b0dc4f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java
@@ -57,18 +57,14 @@ import org.jetbrains.annotations.Nullable;
import org.jsr166.ConcurrentHashMap8;
import static org.apache.ignite.internal.MarshallerPlatformIds.JAVA_ID;
+import static org.apache.ignite.marshaller.MarshallerUtils.CLS_NAMES_FILE;
+import static org.apache.ignite.marshaller.MarshallerUtils.JDK_CLS_NAMES_FILE;
/**
* Marshaller context implementation.
*/
public class MarshallerContextImpl implements MarshallerContext {
/** */
- private static final String CLS_NAMES_FILE = "META-INF/classnames.properties";
-
- /** */
- private static final String JDK_CLS_NAMES_FILE = "META-INF/classnames-jdk.properties";
-
- /** */
private final Map<Integer, MappedName> sysTypesMap = new HashMap<>();
/** */
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java
index fa3f7f3..92a6e6d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/wal/reader/StandaloneGridKernalContext.java
@@ -84,6 +84,7 @@ import org.apache.ignite.internal.suggestions.GridPerformanceSuggestions;
import org.apache.ignite.internal.util.IgniteExceptionRegistry;
import org.apache.ignite.internal.util.StripedExecutor;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.marshaller.Marshaller;
import org.apache.ignite.plugin.PluginNotFoundException;
import org.apache.ignite.plugin.PluginProvider;
@@ -628,4 +629,9 @@ public class StandaloneGridKernalContext implements GridKernalContext {
@NotNull @Override public Iterator<GridComponent> iterator() {
return null;
}
+
+ /** {@inheritDoc} */
+ @Override public IgnitePredicate<String> classNameFilter() {
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
index 0f6a41a..238030a 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java
@@ -8532,6 +8532,18 @@ public abstract class IgniteUtils {
* @throws ClassNotFoundException If class not found.
*/
public static Class<?> forName(String clsName, @Nullable ClassLoader ldr) throws ClassNotFoundException {
+ return U.forName(clsName, ldr, null);
+ }
+
+ /**
+ * Gets class for provided name. Accepts primitive types names.
+ *
+ * @param clsName Class name.
+ * @param ldr Class loader.
+ * @return Class.
+ * @throws ClassNotFoundException If class not found.
+ */
+ public static Class<?> forName(String clsName, @Nullable ClassLoader ldr, IgnitePredicate<String> clsFilter) throws ClassNotFoundException {
assert clsName != null;
Class<?> cls = primitiveMap.get(clsName);
@@ -8558,6 +8570,9 @@ public abstract class IgniteUtils {
cls = ldrMap.get(clsName);
if (cls == null) {
+ if (clsFilter != null && !clsFilter.apply(clsName))
+ throw new RuntimeException("Deserialization of class " + clsName + " is disallowed.");
+
Class old = ldrMap.putIfAbsent(clsName, cls = Class.forName(clsName, true, ldr));
if (old != null)
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java b/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java
index ad63702..bec1f57 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/MarshallerUtils.java
@@ -25,6 +25,12 @@ import org.jetbrains.annotations.Nullable;
* Utility marshaller methods.
*/
public class MarshallerUtils {
+ /** Jdk class names file. */
+ public static final String JDK_CLS_NAMES_FILE = "META-INF/classnames-jdk.properties";
+
+ /** Class names file. */
+ public static final String CLS_NAMES_FILE = "META-INF/classnames.properties";
+
/** Job sender node version. */
private static final ThreadLocal<IgniteProductVersion> JOB_SND_NODE_VER = new ThreadLocal<>();
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java b/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java
index 6759c40..ae4033b 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshaller.java
@@ -27,6 +27,7 @@ import org.apache.ignite.internal.util.io.GridByteArrayInputStream;
import org.apache.ignite.internal.util.io.GridByteArrayOutputStream;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.marshaller.AbstractNodeNameAwareMarshaller;
import org.jetbrains.annotations.Nullable;
@@ -67,6 +68,23 @@ import org.jetbrains.annotations.Nullable;
* For information about Spring framework visit <a href="http://www.springframework.org/">www.springframework.org</a>
*/
public class JdkMarshaller extends AbstractNodeNameAwareMarshaller {
+ /** Class name filter. */
+ private final IgnitePredicate<String> clsFilter;
+
+ /**
+ * Default constructor.
+ */
+ public JdkMarshaller() {
+ this(null);
+ }
+
+ /**
+ * @param clsFilter Class name filter.
+ */
+ public JdkMarshaller(IgnitePredicate<String> clsFilter) {
+ this.clsFilter = clsFilter;
+ }
+
/** {@inheritDoc} */
@Override protected void marshal0(@Nullable Object obj, OutputStream out) throws IgniteCheckedException {
assert out != null;
@@ -116,7 +134,7 @@ public class JdkMarshaller extends AbstractNodeNameAwareMarshaller {
ObjectInputStream objIn = null;
try {
- objIn = new JdkMarshallerObjectInputStream(new JdkMarshallerInputStreamWrapper(in), clsLdr);
+ objIn = new JdkMarshallerObjectInputStream(new JdkMarshallerInputStreamWrapper(in), clsLdr, clsFilter);
return (T)objIn.readObject();
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java b/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java
index 03256e0..d9fdd3d 100644
--- a/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java
+++ b/modules/core/src/main/java/org/apache/ignite/marshaller/jdk/JdkMarshallerObjectInputStream.java
@@ -22,6 +22,7 @@ import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgnitePredicate;
/**
* This class defines custom JDK object input stream.
@@ -30,17 +31,21 @@ class JdkMarshallerObjectInputStream extends ObjectInputStream {
/** */
private final ClassLoader clsLdr;
+ /** Class name filter. */
+ private final IgnitePredicate<String> clsFilter;
+
/**
* @param in Parent input stream.
* @param clsLdr Custom class loader.
* @throws IOException If initialization failed.
*/
- JdkMarshallerObjectInputStream(InputStream in, ClassLoader clsLdr) throws IOException {
+ JdkMarshallerObjectInputStream(InputStream in, ClassLoader clsLdr, IgnitePredicate<String> clsFilter) throws IOException {
super(in);
assert clsLdr != null;
this.clsLdr = clsLdr;
+ this.clsFilter = clsFilter;
enableResolveObject(true);
}
@@ -51,7 +56,7 @@ class JdkMarshallerObjectInputStream extends ObjectInputStream {
// Must have 'Class.forName()' instead of clsLoader.loadClass()
// due to weird ClassNotFoundExceptions for arrays of classes
// in certain cases.
- return U.forName(desc.getName(), clsLdr);
+ return U.forName(desc.getName(), clsLdr, clsFilter);
}
/** {@inheritDoc} */
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
index 713bbab..34b8fdf 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java
@@ -55,6 +55,7 @@ import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.configuration.AddressResolver;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.X;
@@ -333,7 +334,7 @@ public class TcpDiscoverySpi extends IgniteSpiAdapter implements DiscoverySpi {
protected volatile long gridStartTime;
/** Marshaller. */
- private final Marshaller marsh = new JdkMarshaller();
+ private Marshaller marsh;
/** Statistics. */
protected final TcpDiscoveryStatistics stats = new TcpDiscoveryStatistics();
@@ -551,6 +552,11 @@ public class TcpDiscoverySpi extends IgniteSpiAdapter implements DiscoverySpi {
if (ignite != null) {
setLocalAddress(ignite.configuration().getLocalHost());
setAddressResolver(ignite.configuration().getAddressResolver());
+
+ if (ignite instanceof IgniteKernal) // IgniteMock instance can be injected from tests.
+ marsh = new JdkMarshaller(((IgniteKernal)ignite).context().classNameFilter());
+ else
+ marsh = new JdkMarshaller();
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/stream/StreamAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/stream/StreamAdapter.java b/modules/core/src/main/java/org/apache/ignite/stream/StreamAdapter.java
index 3f1dfad..49f0c15 100644
--- a/modules/core/src/main/java/org/apache/ignite/stream/StreamAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/stream/StreamAdapter.java
@@ -46,7 +46,7 @@ public abstract class StreamAdapter<T, K, V> {
private IgniteDataStreamer<K, V> stmr;
/** Ignite. */
- private Ignite ignite;
+ protected Ignite ignite;
/**
* Empty constructor.
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/main/java/org/apache/ignite/stream/socket/SocketStreamer.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/stream/socket/SocketStreamer.java b/modules/core/src/main/java/org/apache/ignite/stream/socket/SocketStreamer.java
index f45423b..827c8d0 100644
--- a/modules/core/src/main/java/org/apache/ignite/stream/socket/SocketStreamer.java
+++ b/modules/core/src/main/java/org/apache/ignite/stream/socket/SocketStreamer.java
@@ -24,6 +24,7 @@ import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteDataStreamer;
import org.apache.ignite.IgniteException;
import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.util.nio.GridBufferedParser;
import org.apache.ignite.internal.util.nio.GridDelimitedParser;
import org.apache.ignite.internal.util.nio.GridNioCodecFilter;
@@ -38,6 +39,7 @@ import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.marshaller.Marshaller;
import org.apache.ignite.marshaller.MarshallerUtils;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
import org.apache.ignite.stream.StreamAdapter;
import org.apache.ignite.stream.StreamTupleExtractor;
import org.jetbrains.annotations.Nullable;
@@ -217,7 +219,7 @@ public class SocketStreamer<T, K, V> extends StreamAdapter<T, K, V> {
/**
* Converts message to Java object using Jdk marshaller.
*/
- private static class DefaultConverter<T> implements SocketMessageConverter<T> {
+ private class DefaultConverter<T> implements SocketMessageConverter<T> {
/** Marshaller. */
private final Marshaller marsh;
@@ -227,7 +229,9 @@ public class SocketStreamer<T, K, V> extends StreamAdapter<T, K, V> {
* @param igniteInstanceName Ignite instance name.
*/
private DefaultConverter(@Nullable String igniteInstanceName) {
- marsh = MarshallerUtils.jdkMarshaller(igniteInstanceName);
+ marsh = new JdkMarshaller(((IgniteKernal)ignite).context().classNameFilter());
+
+ MarshallerUtils.setNodeName(marsh, igniteInstanceName);
}
/** {@inheritDoc} */
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/config/class_list_exploit_excluded.txt
----------------------------------------------------------------------
diff --git a/modules/core/src/test/config/class_list_exploit_excluded.txt b/modules/core/src/test/config/class_list_exploit_excluded.txt
new file mode 100644
index 0000000..d2657e8
--- /dev/null
+++ b/modules/core/src/test/config/class_list_exploit_excluded.txt
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+# Intentionally empty.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/config/class_list_exploit_included.txt
----------------------------------------------------------------------
diff --git a/modules/core/src/test/config/class_list_exploit_included.txt b/modules/core/src/test/config/class_list_exploit_included.txt
new file mode 100644
index 0000000..9a07d54
--- /dev/null
+++ b/modules/core/src/test/config/class_list_exploit_included.txt
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+org.apache.ignite.spi.discovery.tcp.DiscoveryUnmarshalVulnerabilityTest$Exploit
+org.apache.ignite.stream.socket.SocketStreamerUnmarshalVulnerabilityTest$Exploit
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/java/org/apache/ignite/internal/ClassSetTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/ClassSetTest.java b/modules/core/src/test/java/org/apache/ignite/internal/ClassSetTest.java
new file mode 100644
index 0000000..c51957a
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/ClassSetTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.ignite.internal;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link ClassSet} class.
+ */
+public class ClassSetTest extends TestCase {
+ /**
+ * @throws Exception If failed.
+ */
+ public void testAddAndContains() throws Exception {
+ ClassSet clsSet = new ClassSet();
+
+ clsSet.add("org.apache.ignite.Ignite");
+
+ assertTrue(clsSet.contains("org.apache.ignite.Ignite"));
+ assertFalse(clsSet.contains("org.apache.ignite.NotIgnite"));
+ assertFalse(clsSet.contains("org.apache.Ignite"));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testAddWithMaskAndContains() throws Exception {
+ ClassSet clsSet = new ClassSet();
+
+ clsSet.add("org.apache.ignite.*");
+
+ assertTrue(clsSet.contains("org.apache.ignite.Ignite"));
+ assertTrue(clsSet.contains("org.apache.ignite.NotIgnite"));
+ assertFalse(clsSet.contains("org.apache.Ignite"));
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testReduceOnAddWithMask() throws Exception {
+ ClassSet clsSet = new ClassSet();
+
+ clsSet.add("org.apache.ignite.Ignite");
+ clsSet.add("org.apache.ignite.Ignition");
+
+ assertTrue(clsSet.contains("org.apache.ignite.Ignite"));
+ assertTrue(clsSet.contains("org.apache.ignite.Ignition"));
+ assertFalse(clsSet.contains("org.apache.ignite.NotIgnite"));
+
+ clsSet.add("org.apache.ignite.*");
+
+ assertTrue(clsSet.contains("org.apache.ignite.Ignite"));
+ assertTrue(clsSet.contains("org.apache.ignite.Ignition"));
+ assertTrue(clsSet.contains("org.apache.ignite.NotIgnite"));
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java
new file mode 100644
index 0000000..448c9af
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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.ignite.spi.discovery.tcp;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.lang.GridAbsPredicate;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_BLACKLIST;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_WHITELIST;
+
+/**
+ * Tests for whitelist and blacklist ot avoiding deserialization vulnerability.
+ */
+public class DiscoveryUnmarshalVulnerabilityTest extends GridCommonAbstractTest {
+ /** Marshaller. */
+ private static final JdkMarshaller MARSH = new JdkMarshaller();
+
+ /** Shared value. */
+ private static final AtomicBoolean SHARED = new AtomicBoolean();
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ super.beforeTest();
+
+ SHARED.set(false);
+
+ System.clearProperty(IGNITE_MARSHALLER_WHITELIST);
+ System.clearProperty(IGNITE_MARSHALLER_BLACKLIST);
+
+ IgniteUtils.clearClassCache();
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testNoLists() throws Exception {
+ testExploit(true);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testWhiteListIncluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
+
+ testExploit(true);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testWhiteListExcluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_excluded.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
+
+ testExploit(false);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testBlackListIncluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
+
+ testExploit(false);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testBlackListExcluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_excluded.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
+
+ testExploit(true);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testBothListIncluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
+ System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
+
+ testExploit(false);
+ }
+
+ /**
+ * @param positive Positive.
+ */
+ private void testExploit(boolean positive) throws Exception {
+ try {
+ startGrid();
+
+ attack(marshal(new Exploit()));
+
+ boolean res = GridTestUtils.waitForCondition(new GridAbsPredicate() {
+ @Override public boolean apply() {
+ return SHARED.get();
+ }
+ }, 3000L);
+
+ if (positive)
+ assertTrue(res);
+ else
+ assertFalse(res);
+ }
+ finally {
+ stopAllGrids();
+ }
+ }
+
+ /**
+ * @param obj Object.
+ */
+ private static byte[] marshal(Object obj) throws IgniteCheckedException {
+ return MARSH.marshal(obj);
+ }
+
+ /**
+ * @param data Data.
+ */
+ private void attack(byte[] data) throws IOException {
+ InetAddress addr = InetAddress.getLoopbackAddress();
+
+ try (
+ Socket sock = new Socket(addr, 47500);
+ OutputStream oos = new BufferedOutputStream(sock.getOutputStream())
+ ) {
+ oos.write(U.IGNITE_HEADER);
+ oos.write(data);
+ }
+ }
+
+ /** */
+ private static class Exploit implements Serializable {
+ /**
+ * @param is Input stream.
+ */
+ private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException {
+ SHARED.set(true);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/java/org/apache/ignite/stream/socket/SocketStreamerUnmarshalVulnerabilityTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/stream/socket/SocketStreamerUnmarshalVulnerabilityTest.java b/modules/core/src/test/java/org/apache/ignite/stream/socket/SocketStreamerUnmarshalVulnerabilityTest.java
new file mode 100644
index 0000000..dadc5b6
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/stream/socket/SocketStreamerUnmarshalVulnerabilityTest.java
@@ -0,0 +1,222 @@
+/*
+ * 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.ignite.stream.socket;
+
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteDataStreamer;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.util.IgniteUtils;
+import org.apache.ignite.internal.util.lang.GridAbsPredicate;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.apache.ignite.marshaller.Marshaller;
+import org.apache.ignite.marshaller.jdk.JdkMarshaller;
+import org.apache.ignite.stream.StreamSingleTupleExtractor;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_BLACKLIST;
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_WHITELIST;
+
+/**
+ * Tests for whitelist and blacklist ot avoiding deserialization vulnerability.
+ */
+public class SocketStreamerUnmarshalVulnerabilityTest extends GridCommonAbstractTest {
+ /** Shared value. */
+ private static final AtomicBoolean SHARED = new AtomicBoolean();
+
+ /** Port. */
+ private static int port;
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ try (ServerSocket sock = new ServerSocket(0)) {
+ port = sock.getLocalPort();
+ }
+
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ cfg.setCacheConfiguration(defaultCacheConfiguration());
+
+ return cfg;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ super.beforeTest();
+
+ SHARED.set(false);
+
+ System.clearProperty(IGNITE_MARSHALLER_WHITELIST);
+ System.clearProperty(IGNITE_MARSHALLER_BLACKLIST);
+
+ IgniteUtils.clearClassCache();
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testNoLists() throws Exception {
+ testExploit(true);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testWhiteListIncluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
+
+ testExploit(true);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testWhiteListExcluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_excluded.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
+
+ testExploit(false);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testBlackListIncluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
+
+ testExploit(false);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testBlackListExcluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_excluded.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
+
+ testExploit(true);
+ }
+
+ /**
+ * @throws Exception If failed.
+ */
+ public void testBothListIncluded() throws Exception {
+ String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
+
+ System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
+ System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
+
+ testExploit(false);
+ }
+
+ /**
+ * @param positive Positive.
+ */
+ private void testExploit(boolean positive) throws Exception {
+ try {
+ Ignite ignite = startGrid();
+
+ SocketStreamer<Exploit, Integer, String> sockStmr = null;
+
+ try (IgniteDataStreamer<Integer, String> stmr = ignite.dataStreamer(DEFAULT_CACHE_NAME)) {
+ stmr.allowOverwrite(true);
+ stmr.autoFlushFrequency(10);
+
+ sockStmr = new SocketStreamer<>();
+
+ sockStmr.setIgnite(ignite);
+
+ sockStmr.setStreamer(stmr);
+
+ sockStmr.setPort(port);
+
+ sockStmr.setSingleTupleExtractor(new StreamSingleTupleExtractor<Exploit, Integer, String>() {
+ @Override public Map.Entry<Integer, String> extract(Exploit msg) {
+ return new IgniteBiTuple<>(1, "val");
+ }
+ });
+
+ sockStmr.start();
+
+ try (Socket sock = new Socket(InetAddress.getLocalHost(), port);
+ OutputStream os = new BufferedOutputStream(sock.getOutputStream())) {
+ Marshaller marsh = new JdkMarshaller();
+
+ byte[] msg = marsh.marshal(new Exploit());
+
+ os.write(msg.length >>> 24);
+ os.write(msg.length >>> 16);
+ os.write(msg.length >>> 8);
+ os.write(msg.length);
+
+ os.write(msg);
+ }
+ catch (IOException | IgniteCheckedException e) {
+ throw new IgniteException(e);
+ }
+
+ boolean res = GridTestUtils.waitForCondition(new GridAbsPredicate() {
+ @Override public boolean apply() {
+ return SHARED.get();
+ }
+ }, 3000L);
+
+ if (positive)
+ assertTrue(res);
+ else
+ assertFalse(res);
+ }
+ finally {
+ if (sockStmr != null)
+ sockStmr.stop();
+ }
+ }
+ finally {
+ stopAllGrids();
+ }
+ }
+
+ /** */
+ private static class Exploit implements Serializable {
+ /**
+ * @param is Input stream.
+ */
+ private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException {
+ SHARED.set(true);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java
index 6b39faa..cfc0abe 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java
@@ -32,6 +32,7 @@ import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.plugin.PluginProvider;
import org.apache.ignite.testframework.GridTestUtils;
@@ -78,7 +79,8 @@ public class GridTestKernalContext extends GridKernalContextImpl {
null,
null,
null,
- U.allPluginProviders()
+ U.allPluginProviders(),
+ null
);
GridTestUtils.setFieldValue(grid(), "cfg", config());
@@ -132,6 +134,11 @@ public class GridTestKernalContext extends GridKernalContextImpl {
}
/** {@inheritDoc} */
+ @Override public IgnitePredicate<String> classNameFilter() {
+ return super.classNameFilter();
+ }
+
+ /** {@inheritDoc} */
@Override public String toString() {
return S.toString(GridTestKernalContext.class, this, super.toString());
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
index 1b4e2da..9fee224 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
@@ -20,6 +20,7 @@ package org.apache.ignite.testsuites;
import java.util.Set;
import junit.framework.TestSuite;
import org.apache.ignite.GridSuppressedExceptionSelfTest;
+import org.apache.ignite.internal.ClassSetTest;
import org.apache.ignite.internal.ClusterGroupHostsSelfTest;
import org.apache.ignite.internal.ClusterGroupSelfTest;
import org.apache.ignite.internal.GridFailFastNodeFailureDetectionSelfTest;
@@ -191,6 +192,8 @@ public class IgniteBasicTestSuite extends TestSuite {
suite.addTestSuite(GridCleanerTest.class);
+ suite.addTestSuite(ClassSetTest.class);
+
return suite;
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
index 626875c..6e51c36 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiDiscoverySelfTestSuite.java
@@ -21,6 +21,7 @@ import junit.framework.TestSuite;
import org.apache.ignite.spi.GridTcpSpiForwardingSelfTest;
import org.apache.ignite.spi.discovery.AuthenticationRestartTest;
import org.apache.ignite.spi.discovery.IgniteDiscoveryCacheReuseSelfTest;
+import org.apache.ignite.spi.discovery.tcp.DiscoveryUnmarshalVulnerabilityTest;
import org.apache.ignite.spi.discovery.tcp.IgniteClientConnectTest;
import org.apache.ignite.spi.discovery.tcp.IgniteClientReconnectMassiveShutdownTest;
import org.apache.ignite.spi.discovery.tcp.TcpClientDiscoveryMarshallerCheckSelfTest;
@@ -111,6 +112,8 @@ public class IgniteSpiDiscoverySelfTestSuite extends TestSuite {
// Disco cache reuse.
suite.addTest(new TestSuite(IgniteDiscoveryCacheReuseSelfTest.class));
+ suite.addTest(new TestSuite(DiscoveryUnmarshalVulnerabilityTest.class));
+
return suite;
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/ca877b43/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteStreamSelfTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteStreamSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteStreamSelfTestSuite.java
index d7c677c..9eac277 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteStreamSelfTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteStreamSelfTestSuite.java
@@ -19,6 +19,7 @@ package org.apache.ignite.testsuites;
import junit.framework.TestSuite;
import org.apache.ignite.stream.socket.SocketStreamerSelfTest;
+import org.apache.ignite.stream.socket.SocketStreamerUnmarshalVulnerabilityTest;
/**
* Stream test suite.
@@ -32,6 +33,7 @@ public class IgniteStreamSelfTestSuite extends TestSuite {
TestSuite suite = new TestSuite("Ignite Stream Test Suite");
suite.addTest(new TestSuite(SocketStreamerSelfTest.class));
+ suite.addTest(new TestSuite(SocketStreamerUnmarshalVulnerabilityTest.class));
return suite;
}