Skip to content

Commit f1d3579

Browse files
authored
IGNITE-23594 Enhance object input stream filtering (#11642)
1 parent 19f7ad3 commit f1d3579

File tree

58 files changed

+978
-535
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+978
-535
lines changed

Diff for: checkstyle/checkstyle-suppressions.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@
2525
files="BCrypt\.java|ConcurrentLinkedDeque8\.java"/>
2626
<suppress checks="NoWhitespaceBefore" files="ConcurrentLinkedHashMap\.java"/>
2727
<suppress checks="LineLength"
28-
files="ClusterTagGenerator\.java|PagesWriteSpeedBasedThrottle\.java|GridExecutorService\.java|CatboostClassificationModel\.java"/>
28+
files="ClusterTagGenerator\.java|PagesWriteSpeedBasedThrottle\.java|GridExecutorService\.java|CatboostClassificationModel\.java|classnames\.properties"/>
2929
</suppressions>

Diff for: modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java

+3
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@
7777
import org.apache.ignite.lang.IgnitePredicate;
7878
import org.apache.ignite.lang.IgniteUuid;
7979
import org.apache.ignite.testframework.GridTestUtils;
80+
import org.apache.ignite.testframework.junits.WithSystemProperty;
8081
import org.junit.Test;
8182
import org.junit.runner.RunWith;
8283
import org.junit.runners.Parameterized;
8384

85+
import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_OBJECT_INPUT_FILTER_AUTOCONFIGURATION;
8486
import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_BLACKLIST;
8587
import static org.apache.ignite.IgniteSystemProperties.IGNITE_USE_BINARY_ARRAYS;
8688
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
@@ -108,6 +110,7 @@
108110
*/
109111
@SuppressWarnings("unchecked")
110112
@RunWith(Parameterized.class)
113+
@WithSystemProperty(key = IGNITE_ENABLE_OBJECT_INPUT_FILTER_AUTOCONFIGURATION, value = "false")
111114
public abstract class JettyRestProcessorAbstractSelfTest extends JettyRestProcessorCommonSelfTest {
112115
/** */
113116
private static boolean memoryMetricsEnabled;

Diff for: modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/TcpRestUnmarshalVulnerabilityTest.java

+3
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@
3737
import org.apache.ignite.internal.util.lang.GridAbsPredicate;
3838
import org.apache.ignite.internal.util.typedef.internal.U;
3939
import org.apache.ignite.testframework.GridTestUtils;
40+
import org.apache.ignite.testframework.junits.WithSystemProperty;
4041
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
4142
import org.junit.Test;
4243

44+
import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_OBJECT_INPUT_FILTER_AUTOCONFIGURATION;
4345
import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_BLACKLIST;
4446
import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_WHITELIST;
4547
import static org.apache.ignite.internal.processors.rest.protocols.tcp.GridMemcachedMessage.IGNITE_HANDSHAKE_FLAG;
@@ -48,6 +50,7 @@
4850
/**
4951
* Tests for whitelist and blacklist ot avoiding deserialization vulnerability.
5052
*/
53+
@WithSystemProperty(key = IGNITE_ENABLE_OBJECT_INPUT_FILTER_AUTOCONFIGURATION, value = "false")
5154
public class TcpRestUnmarshalVulnerabilityTest extends GridCommonAbstractTest {
5255
/** Marshaller. */
5356
private static final GridClientJdkMarshaller MARSH = new GridClientJdkMarshaller();

Diff for: modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java

+15
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,21 @@ public final class IgniteSystemProperties {
916916
type = String.class)
917917
public static final String IGNITE_MARSHALLER_BLACKLIST = "IGNITE_MARSHALLER_BLACKLIST";
918918

919+
/**
920+
* If this parameter is set to true, Ignite will automatically configure an ObjectInputFilter instance for the
921+
* current JVM it is running in.
922+
* Default value is {@code true}.
923+
*/
924+
@SystemProperty(
925+
value = "If this parameter is set to true, Ignite will automatically configure an ObjectInputFilter" +
926+
" instance for the current JVM it is running in. Filtering is based on class lists defined by the" +
927+
" `IGNITE_MARSHALLER_WHITELIST` and `IGNITE_MARSHALLER_BLACKLIST` system properties or their default values." +
928+
" Disabling it is not recommended because the Ignite host may be vulnerable to RCE attacks based on Java" +
929+
" serialization mechanisms",
930+
defaults = "true"
931+
)
932+
public static final String IGNITE_ENABLE_OBJECT_INPUT_FILTER_AUTOCONFIGURATION = "IGNITE_ENABLE_OBJECT_INPUT_FILTER_AUTOCONFIGURATION";
933+
919934
/**
920935
* If set to {@code true}, then default selected keys set is used inside
921936
* {@code GridNioServer} which lead to some extra garbage generation when

Diff for: modules/core/src/main/java/org/apache/ignite/internal/ClassSet.java

+37
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Collections;
2121
import java.util.HashMap;
2222
import java.util.Map;
23+
import java.util.Objects;
2324

2425
/**
2526
* Set of classes represented as prefix tree.
@@ -99,9 +100,45 @@ public boolean contains(String clsName) {
99100
return false;
100101
}
101102

103+
/** {@inheritDoc} */
104+
@Override public boolean equals(Object o) {
105+
if (this == o)
106+
return true;
107+
108+
if (!(o instanceof ClassSet))
109+
return false;
110+
111+
ClassSet other = (ClassSet)o;
112+
113+
return Objects.equals(root, other.root);
114+
}
115+
116+
/** {@inheritDoc} */
117+
@Override public int hashCode() {
118+
return Objects.hashCode(root);
119+
}
120+
102121
/** */
103122
private static class Node {
104123
/** Children. */
105124
private Map<String, Node> children;
125+
126+
/** {@inheritDoc} */
127+
@Override public boolean equals(Object o) {
128+
if (this == o)
129+
return true;
130+
131+
if (!(o instanceof Node))
132+
return false;
133+
134+
Node other = (Node)o;
135+
136+
return Objects.equals(children, other.children);
137+
}
138+
139+
/** {@inheritDoc} */
140+
@Override public int hashCode() {
141+
return Objects.hashCode(children);
142+
}
106143
}
107144
}

Diff for: modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java

+31-5
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,10 @@
201201
import org.apache.ignite.lifecycle.LifecycleAware;
202202
import org.apache.ignite.lifecycle.LifecycleBean;
203203
import org.apache.ignite.lifecycle.LifecycleEventType;
204+
import org.apache.ignite.marshaller.IgniteMarshallerClassFilter;
205+
import org.apache.ignite.marshaller.Marshaller;
204206
import org.apache.ignite.marshaller.MarshallerExclusions;
205207
import org.apache.ignite.marshaller.MarshallerUtils;
206-
import org.apache.ignite.marshaller.jdk.JdkMarshaller;
207208
import org.apache.ignite.metric.IgniteMetrics;
208209
import org.apache.ignite.metric.MetricRegistry;
209210
import org.apache.ignite.plugin.IgnitePlugin;
@@ -926,14 +927,18 @@ public void start(
926927

927928
List<PluginProvider> plugins = U.allPluginProviders(cfg, true);
928929

930+
IgniteMarshallerClassFilter clsFilter = MarshallerUtils.classNameFilter(getClass().getClassLoader());
931+
932+
MarshallerUtils.autoconfigureObjectInputFilter(clsFilter);
933+
929934
// Spin out SPIs & managers.
930935
try {
931936
ctx = new GridKernalContextImpl(log,
932937
this,
933938
cfg,
934939
gw,
935940
plugins,
936-
MarshallerUtils.classNameFilter(this.getClass().getClassLoader()),
941+
clsFilter,
937942
workerRegistry,
938943
hnd,
939944
longJVMPauseDetector
@@ -943,7 +948,7 @@ public void start(
943948

944949
mBeansMgr = new IgniteMBeansManager(this);
945950

946-
cfg.getMarshaller().setContext(ctx.marshallerContext());
951+
initializeMarshaller();
947952

948953
startProcessor(new GridInternalSubscriptionProcessor(ctx));
949954

@@ -1444,7 +1449,6 @@ private void validateCommon(IgniteConfiguration cfg) {
14441449
A.notNull(cfg.getMBeanServer(), "cfg.getMBeanServer()");
14451450

14461451
A.notNull(cfg.getGridLogger(), "cfg.getGridLogger()");
1447-
A.notNull(cfg.getMarshaller(), "cfg.getMarshaller()");
14481452
A.notNull(cfg.getUserAttributes(), "cfg.getUserAttributes()");
14491453

14501454
// All SPIs should be non-null.
@@ -1520,6 +1524,28 @@ private void checkPhysicalRam() {
15201524
}
15211525
}
15221526

1527+
/** */
1528+
private void initializeMarshaller() {
1529+
Marshaller marsh = ctx.config().getMarshaller();
1530+
1531+
if (marsh == null) {
1532+
if (!BinaryMarshaller.available()) {
1533+
U.warn(log, "Standard BinaryMarshaller can't be used on this JVM. " +
1534+
"Switch to HotSpot JVM or reach out Apache Ignite community for recommendations.");
1535+
1536+
marsh = ctx.marshallerContext().jdkMarshaller();
1537+
}
1538+
else
1539+
marsh = new BinaryMarshaller();
1540+
1541+
ctx.config().setMarshaller(marsh);
1542+
}
1543+
1544+
marsh.setContext(ctx.marshallerContext());
1545+
1546+
MarshallerUtils.setNodeName(marsh, ctx.igniteInstanceName());
1547+
}
1548+
15231549
/**
15241550
* @param cfg Ignite configuration to check for possible performance issues.
15251551
*/
@@ -1750,7 +1776,7 @@ private void addDataStorageConfigurationAttributes() throws IgniteCheckedExcepti
17501776
}
17511777

17521778
// Save data storage configuration.
1753-
add(ATTR_DATA_STORAGE_CONFIG, new JdkMarshaller().marshal(cfg.getDataStorageConfiguration()));
1779+
add(ATTR_DATA_STORAGE_CONFIG, ctx.marshallerContext().jdkMarshaller().marshal(cfg.getDataStorageConfiguration()));
17541780
}
17551781

17561782
/**

Diff for: modules/core/src/main/java/org/apache/ignite/internal/IgnitionEx.java

+1-22
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@
7474
import org.apache.ignite.failure.FailureContext;
7575
import org.apache.ignite.failure.FailureType;
7676
import org.apache.ignite.internal.binary.BinaryArray;
77-
import org.apache.ignite.internal.binary.BinaryMarshaller;
7877
import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
7978
import org.apache.ignite.internal.processors.cache.CacheGroupContext;
8079
import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionFullMap;
@@ -104,9 +103,6 @@
104103
import org.apache.ignite.internal.worker.WorkersRegistry;
105104
import org.apache.ignite.lang.IgniteBiInClosure;
106105
import org.apache.ignite.lang.IgniteBiTuple;
107-
import org.apache.ignite.marshaller.Marshaller;
108-
import org.apache.ignite.marshaller.MarshallerUtils;
109-
import org.apache.ignite.marshaller.jdk.JdkMarshaller;
110106
import org.apache.ignite.mxbean.IgnitionMXBean;
111107
import org.apache.ignite.plugin.segmentation.SegmentationPolicy;
112108
import org.apache.ignite.resources.SpringApplicationContextResource;
@@ -1914,27 +1910,10 @@ private IgniteConfiguration initializeConfiguration(IgniteConfiguration cfg)
19141910
}
19151911

19161912
if (myCfg.getUserAttributes() == null)
1917-
myCfg.setUserAttributes(Collections.<String, Object>emptyMap());
1913+
myCfg.setUserAttributes(Collections.emptyMap());
19181914

19191915
initializeDefaultMBeanServer(myCfg);
19201916

1921-
Marshaller marsh = myCfg.getMarshaller();
1922-
1923-
if (marsh == null) {
1924-
if (!BinaryMarshaller.available()) {
1925-
U.warn(log, "Standard BinaryMarshaller can't be used on this JVM. " +
1926-
"Switch to HotSpot JVM or reach out Apache Ignite community for recommendations.");
1927-
1928-
marsh = new JdkMarshaller();
1929-
}
1930-
else
1931-
marsh = new BinaryMarshaller();
1932-
}
1933-
1934-
MarshallerUtils.setNodeName(marsh, cfg.getIgniteInstanceName());
1935-
1936-
myCfg.setMarshaller(marsh);
1937-
19381917
if (myCfg.getPeerClassLoadingLocalClassPathExclude() == null)
19391918
myCfg.setPeerClassLoadingLocalClassPathExclude(EMPTY_STRS);
19401919

Diff for: modules/core/src/main/java/org/apache/ignite/internal/MarshallerContextImpl.java

+2
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,8 @@ public void onMarshallerProcessorStarted(
600600

601601
if (CU.isPersistenceEnabled(ctx.config()))
602602
fileStore.restoreMappings(this);
603+
604+
MarshallerUtils.setNodeName(jdkMarsh, ctx.igniteInstanceName());
603605
}
604606

605607
/**

Diff for: modules/core/src/main/java/org/apache/ignite/internal/cdc/CdcMain.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@
7373
import org.apache.ignite.internal.util.typedef.internal.U;
7474
import org.apache.ignite.lang.IgniteBiPredicate;
7575
import org.apache.ignite.lang.IgniteBiTuple;
76-
import org.apache.ignite.marshaller.MarshallerUtils;
7776
import org.apache.ignite.platform.PlatformType;
7877
import org.apache.ignite.spi.IgniteSpi;
7978
import org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi;
@@ -762,7 +761,7 @@ private void updateCaches() {
762761
Iterator<CdcCacheEvent> cacheEvts = GridLocalConfigManager
763762
.readCachesData(
764763
dbDir,
765-
MarshallerUtils.jdkMarshaller(kctx.igniteInstanceName()),
764+
kctx.marshallerContext().jdkMarshaller(),
766765
igniteCfg)
767766
.entrySet().stream()
768767
.map(data -> {

Diff for: modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@
120120
import org.apache.ignite.lang.IgniteProductVersion;
121121
import org.apache.ignite.lang.IgniteUuid;
122122
import org.apache.ignite.marshaller.Marshaller;
123-
import org.apache.ignite.marshaller.MarshallerUtils;
124123
import org.apache.ignite.plugin.security.SecurityCredentials;
125124
import org.apache.ignite.plugin.segmentation.SegmentationPolicy;
126125
import org.apache.ignite.spi.IgniteSpiException;
@@ -548,7 +547,7 @@ private void updateClientNodes(UUID leftNodeId) {
548547
spi.setListener(new DiscoverySpiListener() {
549548
private long gridStartTime;
550549

551-
private final Marshaller marshaller = MarshallerUtils.jdkMarshaller(ctx.igniteInstanceName());
550+
private final Marshaller marshaller = ctx.marshallerContext().jdkMarshaller();
552551

553552
/** {@inheritDoc} */
554553
@Override public void onLocalNodeInitialized(ClusterNode locNode) {

Diff for: modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedObjectInputStream.java

+9
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,15 @@ void readFields(Object obj, OptimizedClassDescriptor.ClassFields fieldOffs) thro
533533
}
534534
}
535535

536+
/** {@inheritDoc} */
537+
@Override protected Class<?> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException {
538+
// NOTE: DO NOT CHANGE TO 'clsLoader.loadClass()'
539+
// Must have 'Class.forName()' instead of clsLoader.loadClass()
540+
// due to weird ClassNotFoundExceptions for arrays of classes
541+
// in certain cases.
542+
return U.forName(desc.getName(), clsLdr, ctx.classNameFilter());
543+
}
544+
536545
/**
537546
* Reads {@link Externalizable} object.
538547
*

Diff for: modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@
8282
import org.apache.ignite.lang.IgniteInClosure;
8383
import org.apache.ignite.lang.IgniteProductVersion;
8484
import org.apache.ignite.lang.IgniteUuid;
85-
import org.apache.ignite.marshaller.jdk.JdkMarshaller;
8685
import org.apache.ignite.plugin.CachePluginContext;
8786
import org.apache.ignite.plugin.CachePluginProvider;
8887
import org.apache.ignite.plugin.PluginProvider;
@@ -2540,7 +2539,7 @@ else if (exchActions == null) {
25402539

25412540
if (dsCfgBytes instanceof byte[]) {
25422541
try {
2543-
DataStorageConfiguration crdDsCfg = new JdkMarshaller().unmarshal(
2542+
DataStorageConfiguration crdDsCfg = ctx.marshallerContext().jdkMarshaller().unmarshal(
25442543
(byte[])dsCfgBytes, U.resolveClassLoader(ctx.config()));
25452544

25462545
return CU.isPersistentCache(startedCacheCfg, crdDsCfg);

Diff for: modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@
181181
import org.apache.ignite.lang.IgniteUuid;
182182
import org.apache.ignite.lifecycle.LifecycleAware;
183183
import org.apache.ignite.marshaller.Marshaller;
184-
import org.apache.ignite.marshaller.MarshallerUtils;
185184
import org.apache.ignite.metric.MetricRegistry;
186185
import org.apache.ignite.mxbean.IgniteMBeanAware;
187186
import org.apache.ignite.plugin.security.SecurityException;
@@ -346,7 +345,7 @@ public GridCacheProcessor(GridKernalContext ctx) {
346345
jCacheProxies = new ConcurrentHashMap<>();
347346
internalCaches = new HashSet<>();
348347

349-
marsh = MarshallerUtils.jdkMarshaller(ctx.igniteInstanceName());
348+
marsh = ctx.marshallerContext().jdkMarshaller();
350349
splitter = new CacheConfigurationSplitterImpl(ctx, marsh);
351350
enricher = new CacheConfigurationEnricher(ctx, marsh, U.resolveClassLoader(ctx.config()));
352351
}

Diff for: modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridLocalConfigManager.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@
6565
import org.apache.ignite.internal.util.typedef.internal.U;
6666
import org.apache.ignite.lang.IgniteUuid;
6767
import org.apache.ignite.marshaller.Marshaller;
68-
import org.apache.ignite.marshaller.MarshallerUtils;
6968
import org.jetbrains.annotations.Nullable;
7069

7170
import static java.nio.file.Files.newDirectoryStream;
@@ -124,7 +123,7 @@ public GridLocalConfigManager(
124123
this.cacheProcessor = cacheProcessor;
125124
ctx = kernalCtx;
126125
log = ctx.log(getClass());
127-
marshaller = MarshallerUtils.jdkMarshaller(ctx.igniteInstanceName());
126+
marshaller = ctx.marshallerContext().jdkMarshaller();
128127

129128
PdsFolderSettings<?> folderSettings = ctx.pdsFolderResolver().resolveFolders();
130129

Diff for: modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ValidationOnNodeJoinUtils.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@
5757
import org.apache.ignite.internal.util.typedef.internal.U;
5858
import org.apache.ignite.lang.IgniteProductVersion;
5959
import org.apache.ignite.marshaller.Marshaller;
60-
import org.apache.ignite.marshaller.jdk.JdkMarshaller;
6160
import org.apache.ignite.plugin.security.SecurityException;
6261
import org.apache.ignite.spi.IgniteNodeValidationResult;
6362
import org.apache.ignite.spi.discovery.DiscoveryDataBag;
@@ -604,7 +603,7 @@ private static void checkMemoryConfiguration(ClusterNode rmt, GridKernalContext
604603
Object dsCfgBytes = rmt.attribute(IgniteNodeAttributes.ATTR_DATA_STORAGE_CONFIG);
605604

606605
if (dsCfgBytes instanceof byte[])
607-
dsCfg = new JdkMarshaller().unmarshal((byte[])dsCfgBytes, U.resolveClassLoader(ctx.config()));
606+
dsCfg = ctx.marshallerContext().jdkMarshaller().unmarshal((byte[])dsCfgBytes, U.resolveClassLoader(ctx.config()));
608607

609608
if (dsCfg == null) {
610609
// Try to use legacy memory configuration.

Diff for: modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,8 @@ private DataRegionConfiguration createDefragmentationMappingRegionConfig(long re
565565
kernalCtx.failure(),
566566
kernalCtx.cache(),
567567
() -> cpFreqDeviation.getOrDefault(DEFAULT_CHECKPOINT_DEVIATION),
568-
kernalCtx.pools().getSystemExecutorService()
568+
kernalCtx.pools().getSystemExecutorService(),
569+
kernalCtx.marshallerContext().jdkMarshaller()
569570
);
570571

571572
final NodeFileLockHolder preLocked = kernalCtx.pdsFolderResolver()

0 commit comments

Comments
 (0)