Skip to content

Commit 82a7b82

Browse files
committed
IGNITE-8565 Client marshalling improvements
1 parent 4a44266 commit 82a7b82

File tree

10 files changed

+494
-115
lines changed

10 files changed

+494
-115
lines changed

modules/clients/src/test/java/org/apache/ignite/internal/client/suite/IgniteClientTestSuite.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.apache.ignite.internal.processors.rest.RestProcessorMultiStartSelfTest;
5959
import org.apache.ignite.internal.processors.rest.RestProcessorStartSelfTest;
6060
import org.apache.ignite.internal.processors.rest.TaskCommandHandlerSelfTest;
61+
import org.apache.ignite.internal.processors.rest.TcpRestUnmarshalVulnerabilityTest;
6162
import org.apache.ignite.internal.processors.rest.protocols.tcp.TcpRestParserSelfTest;
6263
import org.apache.ignite.internal.processors.rest.protocols.tcp.redis.RedisProtocolConnectSelfTest;
6364
import org.apache.ignite.internal.processors.rest.protocols.tcp.redis.RedisProtocolServerSelfTest;
@@ -84,6 +85,7 @@ public static TestSuite suite() {
8485

8586
// Test custom binary protocol with test client.
8687
suite.addTestSuite(RestBinaryProtocolSelfTest.class);
88+
suite.addTestSuite(TcpRestUnmarshalVulnerabilityTest.class);
8789

8890
// Test jetty rest processor
8991
suite.addTestSuite(JettyRestProcessorSignedSelfTest.class);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.ignite.internal.processors.rest;
19+
20+
import java.io.BufferedInputStream;
21+
import java.io.BufferedOutputStream;
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.io.ObjectInputStream;
25+
import java.io.OutputStream;
26+
import java.net.InetAddress;
27+
import java.net.Socket;
28+
import java.nio.ByteBuffer;
29+
import java.util.UUID;
30+
import java.util.concurrent.atomic.AtomicBoolean;
31+
import org.apache.ignite.configuration.ConnectorConfiguration;
32+
import org.apache.ignite.configuration.IgniteConfiguration;
33+
import org.apache.ignite.internal.client.marshaller.jdk.GridClientJdkMarshaller;
34+
import org.apache.ignite.internal.processors.rest.client.message.GridClientHandshakeRequest;
35+
import org.apache.ignite.internal.processors.rest.client.message.GridClientMessage;
36+
import org.apache.ignite.internal.util.IgniteUtils;
37+
import org.apache.ignite.internal.util.lang.GridAbsPredicate;
38+
import org.apache.ignite.internal.util.typedef.internal.U;
39+
import org.apache.ignite.testframework.GridTestUtils;
40+
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
41+
42+
import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_BLACKLIST;
43+
import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_WHITELIST;
44+
import static org.apache.ignite.internal.processors.rest.protocols.tcp.GridMemcachedMessage.IGNITE_HANDSHAKE_FLAG;
45+
import static org.apache.ignite.internal.processors.rest.protocols.tcp.GridMemcachedMessage.IGNITE_REQ_FLAG;
46+
47+
/**
48+
* Tests for whitelist and blacklist ot avoiding deserialization vulnerability.
49+
*/
50+
public class TcpRestUnmarshalVulnerabilityTest extends GridCommonAbstractTest {
51+
/** Marshaller. */
52+
private static final GridClientJdkMarshaller MARSH = new GridClientJdkMarshaller();
53+
54+
/** Shared value. */
55+
private static final AtomicBoolean SHARED = new AtomicBoolean();
56+
57+
/** Port. */
58+
private static int port;
59+
60+
/** Host. */
61+
private static String host;
62+
63+
/** {@inheritDoc} */
64+
@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
65+
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
66+
67+
ConnectorConfiguration connCfg = new ConnectorConfiguration();
68+
69+
port = connCfg.getPort();
70+
host = connCfg.getHost();
71+
72+
cfg.setConnectorConfiguration(connCfg);
73+
74+
return cfg;
75+
}
76+
77+
/** {@inheritDoc} */
78+
@Override protected void beforeTest() throws Exception {
79+
super.beforeTest();
80+
81+
SHARED.set(false);
82+
83+
System.clearProperty(IGNITE_MARSHALLER_WHITELIST);
84+
System.clearProperty(IGNITE_MARSHALLER_BLACKLIST);
85+
86+
IgniteUtils.clearClassCache();
87+
}
88+
89+
/**
90+
* @throws Exception If failed.
91+
*/
92+
public void testNoLists() throws Exception {
93+
testExploit(true);
94+
}
95+
96+
/**
97+
* @throws Exception If failed.
98+
*/
99+
public void testWhiteListIncluded() throws Exception {
100+
String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
101+
102+
System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
103+
104+
testExploit(true);
105+
}
106+
107+
/**
108+
* @throws Exception If failed.
109+
*/
110+
public void testWhiteListExcluded() throws Exception {
111+
String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_excluded.txt").getPath();
112+
113+
System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
114+
115+
testExploit(false);
116+
}
117+
118+
/**
119+
* @throws Exception If failed.
120+
*/
121+
public void testBlackListIncluded() throws Exception {
122+
String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
123+
124+
System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
125+
126+
testExploit(false);
127+
}
128+
129+
/**
130+
* @throws Exception If failed.
131+
*/
132+
public void testBlackListExcluded() throws Exception {
133+
String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_excluded.txt").getPath();
134+
135+
System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
136+
137+
testExploit(true);
138+
}
139+
140+
/**
141+
* @throws Exception If failed.
142+
*/
143+
public void testBothListIncluded() throws Exception {
144+
String path = U.resolveIgnitePath("modules/core/src/test/config/class_list_exploit_included.txt").getPath();
145+
146+
System.setProperty(IGNITE_MARSHALLER_WHITELIST, path);
147+
System.setProperty(IGNITE_MARSHALLER_BLACKLIST, path);
148+
149+
testExploit(false);
150+
}
151+
152+
/**
153+
* @param positive Positive.
154+
*/
155+
private void testExploit(boolean positive) throws Exception {
156+
try {
157+
startGrid();
158+
159+
attack(marshal(new Exploit()).array());
160+
161+
boolean res = GridTestUtils.waitForCondition(new GridAbsPredicate() {
162+
@Override public boolean apply() {
163+
return SHARED.get();
164+
}
165+
}, 3000L);
166+
167+
if (positive)
168+
assertTrue(res);
169+
else
170+
assertFalse(res);
171+
}
172+
finally {
173+
stopAllGrids();
174+
}
175+
}
176+
177+
/**
178+
* @param obj Object.
179+
*/
180+
private static ByteBuffer marshal(Object obj) throws IOException {
181+
return MARSH.marshal(obj, 0);
182+
}
183+
184+
/**
185+
* @param data Data.
186+
*/
187+
private void attack(byte[] data) throws IOException {
188+
InetAddress addr = InetAddress.getByName(host);
189+
190+
try (
191+
Socket sock = new Socket(addr, port);
192+
OutputStream os = new BufferedOutputStream(sock.getOutputStream())
193+
) {
194+
// Handshake request.
195+
os.write(IGNITE_HANDSHAKE_FLAG);
196+
197+
GridClientHandshakeRequest req = new GridClientHandshakeRequest();
198+
req.marshallerId(GridClientJdkMarshaller.ID);
199+
os.write(req.rawBytes());
200+
os.flush();
201+
202+
// Handshake response
203+
InputStream is = new BufferedInputStream(sock.getInputStream());
204+
205+
is.read(new byte[146]); // Read handshake response.
206+
207+
int len = data.length + 40;
208+
209+
os.write(IGNITE_REQ_FLAG); // Package type.
210+
os.write((byte)(len >> 24)); // Package length.
211+
os.write((byte)(len >> 16));
212+
os.write((byte)(len >> 8));
213+
os.write((byte)(len));
214+
os.write(new byte[40]); // Stream header.
215+
os.write(data); // Exploit.
216+
os.flush();
217+
}
218+
}
219+
220+
/** */
221+
private static class Exploit implements GridClientMessage {
222+
/**
223+
* @param is Input stream.
224+
*/
225+
private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException {
226+
SHARED.set(true);
227+
}
228+
229+
/** {@inheritDoc} */
230+
@Override public long requestId() {
231+
return 0;
232+
}
233+
234+
/** {@inheritDoc} */
235+
@Override public void requestId(long reqId) {
236+
// No-op.
237+
}
238+
239+
/** {@inheritDoc} */
240+
@Override public UUID clientId() {
241+
return null;
242+
}
243+
244+
/** {@inheritDoc} */
245+
@Override public void clientId(UUID id) {
246+
// No-op.
247+
}
248+
249+
/** {@inheritDoc} */
250+
@Override public UUID destinationId() {
251+
return null;
252+
}
253+
254+
/** {@inheritDoc} */
255+
@Override public void destinationId(UUID id) {
256+
// No-op.
257+
}
258+
259+
/** {@inheritDoc} */
260+
@Override public byte[] sessionToken() {
261+
return new byte[0];
262+
}
263+
264+
/** {@inheritDoc} */
265+
@Override public void sessionToken(byte[] sesTok) {
266+
// No-op.
267+
}
268+
}
269+
}

modules/clients/src/test/java/org/apache/ignite/loadtests/client/ClientMarshallerBenchmarkTest.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@
2222
import java.util.HashMap;
2323
import java.util.Map;
2424
import java.util.UUID;
25+
import org.apache.ignite.IgniteCheckedException;
26+
import org.apache.ignite.IgniteException;
2527
import org.apache.ignite.internal.client.marshaller.GridClientMarshaller;
2628
import org.apache.ignite.internal.client.marshaller.jdk.GridClientJdkMarshaller;
2729
import org.apache.ignite.internal.client.marshaller.optimized.GridClientOptimizedMarshaller;
2830
import org.apache.ignite.internal.processors.rest.client.message.GridClientCacheRequest;
2931
import org.apache.ignite.internal.util.typedef.X;
32+
import org.apache.ignite.marshaller.MarshallerUtils;
3033
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
3134

3235
import static org.apache.ignite.internal.processors.rest.client.message.GridClientCacheRequest.GridCacheOperation.CAS;
@@ -41,10 +44,15 @@ public class ClientMarshallerBenchmarkTest extends GridCommonAbstractTest {
4144
/**
4245
*/
4346
public ClientMarshallerBenchmarkTest() {
44-
marshallers = new GridClientMarshaller[] {
45-
new GridClientJdkMarshaller(),
46-
new GridClientOptimizedMarshaller()
47-
};
47+
try {
48+
marshallers = new GridClientMarshaller[] {
49+
new GridClientJdkMarshaller(MarshallerUtils.classNameFilter(this.getClass().getClassLoader())),
50+
new GridClientOptimizedMarshaller()
51+
};
52+
}
53+
catch (IgniteCheckedException e) {
54+
throw new IgniteException(e);
55+
}
4856
}
4957

5058
/**

0 commit comments

Comments
 (0)