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/b98a003c
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/b98a003c
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/b98a003c

Branch: refs/heads/ignite-6644
Commit: b98a003c31fabacab0cc1adc96479b14d6f61576
Parents: fc09631
Author: Andrey Gura <[email protected]>
Authored: Mon Jan 22 22:41:54 2018 +0300
Committer: Andrey Gura <[email protected]>
Committed: Wed Jan 24 18:01:59 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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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/b98a003c/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;
     }

Reply via email to