You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@seata.apache.org by ji...@apache.org on 2024/07/27 15:27:07 UTC
(incubator-seata) branch 2.x updated: security: fix REC security vulnerability during Raft deserialization (#6702)
This is an automated email from the ASF dual-hosted git repository.
jianbin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push:
new 20cd9625d2 security: fix REC security vulnerability during Raft deserialization (#6702)
20cd9625d2 is described below
commit 20cd9625d23f99b71fefc83b8db96c14092a9950
Author: funkye <ji...@apache.org>
AuthorDate: Sat Jul 27 23:27:03 2024 +0800
security: fix REC security vulnerability during Raft deserialization (#6702)
---
changes/en-us/2.x.md | 2 +-
changes/zh-cn/2.x.md | 1 +
.../apache/seata/common/exception/ErrorCode.java | 13 ++++++--
.../main/resources/error/ErrorCode_en.properties | 3 +-
.../raft/sync/RaftSyncMessageSerializer.java | 38 ++++++++++++++++++----
.../seata/server/raft/RaftSyncMessageTest.java | 16 +++++++++
.../org/apache/seata/server/raft/TestSecurity.java | 32 ++++++++++++++++++
7 files changed, 95 insertions(+), 10 deletions(-)
diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index c1d0c67f67..8deec047e5 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -36,7 +36,7 @@ Add changes here for all PR submitted to the 2.x branch.
### refactor:
### security:
-
+- [[#6702](https://github.com/apache/incubator-seata/pull/6702)] fix REC security vulnerability during Raft deserialization
### test:
- [[#6608](https://github.com/apache/incubator-seata/pull/6608)] add unit test for sql-parser-core
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index bf9324fed4..d1118bb3d4 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -38,6 +38,7 @@
### security:
+- [[#6702](https://github.com/apache/incubator-seata/pull/6702)] 修复Raft反序列化时存在RCE安全漏洞
### test:
- [[#6608](https://github.com/apache/incubator-seata/pull/6608)] 添加sql-parser-core模块测试用例
diff --git a/common/src/main/java/org/apache/seata/common/exception/ErrorCode.java b/common/src/main/java/org/apache/seata/common/exception/ErrorCode.java
index 72d454d078..fb69cd328f 100644
--- a/common/src/main/java/org/apache/seata/common/exception/ErrorCode.java
+++ b/common/src/main/java/org/apache/seata/common/exception/ErrorCode.java
@@ -24,11 +24,16 @@ public enum ErrorCode {
/**
* 0001 ~ 0099 Configuration related errors
*/
- ERR_CONFIG(ErrorType.Config, 0001);
+ ERR_CONFIG(ErrorType.Config, 0001),
+
/**
- * The error code of the transaction exception.
+ * 0100 ~ 0199 Security related errors
*/
+ ERR_DESERIALIZATION_SECURITY(ErrorType.Security, 0156);
+ /**
+ * The error code of the transaction exception.
+ */
private int code;
private ErrorType type;
@@ -77,6 +82,10 @@ public enum ErrorCode {
* Network error type.
*/
Network,
+ /**
+ * Security related error type.
+ */
+ Security,
/**
* Tm error type.
*/
diff --git a/common/src/main/resources/error/ErrorCode_en.properties b/common/src/main/resources/error/ErrorCode_en.properties
index fd59148996..424ac23455 100644
--- a/common/src/main/resources/error/ErrorCode_en.properties
+++ b/common/src/main/resources/error/ErrorCode_en.properties
@@ -16,4 +16,5 @@
#
ERR_PREFIX=ERR-CODE: [Seata-{code}][{key}]
ERR_POSTFIX=More: [https://seata.apache.org/docs/next/overview/faq#{code}]
-ERR_CONFIG=config error, {0}
\ No newline at end of file
+ERR_CONFIG=config error, {0}
+ERR_DESERIALIZATION_SECURITY=deserialization security error, {0}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/seata/server/cluster/raft/sync/RaftSyncMessageSerializer.java b/server/src/main/java/org/apache/seata/server/cluster/raft/sync/RaftSyncMessageSerializer.java
index 5251d55f98..cd3a7eb4af 100644
--- a/server/src/main/java/org/apache/seata/server/cluster/raft/sync/RaftSyncMessageSerializer.java
+++ b/server/src/main/java/org/apache/seata/server/cluster/raft/sync/RaftSyncMessageSerializer.java
@@ -21,7 +21,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Optional;
+import org.apache.seata.common.exception.ErrorCode;
+import org.apache.seata.common.exception.SeataRuntimeException;
import org.apache.seata.common.loader.EnhancedServiceLoader;
import org.apache.seata.core.compressor.CompressorFactory;
import org.apache.seata.core.serializer.Serializer;
@@ -36,6 +41,14 @@ public class RaftSyncMessageSerializer {
private static final Logger LOGGER = LoggerFactory.getLogger(RaftSyncMessageSerializer.class);
+ private static final List<String> PERMITS = new ArrayList<>();
+
+ static {
+ PERMITS.add(RaftSyncMessage.class.getName());
+ PERMITS.add(io.seata.server.cluster.raft.sync.msg.RaftSyncMessage.class.getName());
+ PERMITS.add("[B");
+ }
+
public static byte[] encode(RaftSyncMessage raftSyncMessage) throws IOException {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
@@ -62,12 +75,22 @@ public class RaftSyncMessageSerializer {
public static RaftSyncMessage decode(byte[] raftSyncMsgByte) {
try (ByteArrayInputStream bin = new ByteArrayInputStream(raftSyncMsgByte);
- ObjectInputStream ois = new ObjectInputStream(bin)) {
+ ObjectInputStream ois = new ObjectInputStream(bin) {
+ @Override
+ protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+ if (!PERMITS.contains(desc.getName())) {
+ throw new SeataRuntimeException(ErrorCode.ERR_DESERIALIZATION_SECURITY,
+ "Failed to deserialize object: " + desc.getName() + " is not permitted");
+ }
+
+ return super.resolveClass(desc);
+ }
+ }) {
Object object = ois.readObject();
RaftSyncMessage raftSyncMessage;
if (object instanceof io.seata.server.cluster.raft.sync.msg.RaftSyncMessage) {
io.seata.server.cluster.raft.sync.msg.RaftSyncMessage oldRaftSyncMessage =
- (io.seata.server.cluster.raft.sync.msg.RaftSyncMessage)object;
+ (io.seata.server.cluster.raft.sync.msg.RaftSyncMessage)object;
raftSyncMessage = new RaftSyncMessage();
raftSyncMessage.setCodec(oldRaftSyncMessage.getCodec());
raftSyncMessage.setCompressor(oldRaftSyncMessage.getCompressor());
@@ -77,13 +100,16 @@ public class RaftSyncMessageSerializer {
raftSyncMessage = (RaftSyncMessage)object;
}
Serializer serializer = EnhancedServiceLoader.load(Serializer.class,
- SerializerType.getByCode(raftSyncMessage.getCodec()).name());
+ SerializerType.getByCode(raftSyncMessage.getCodec()).name());
Optional.ofNullable(raftSyncMessage.getBody())
- .ifPresent(value -> raftSyncMessage.setBody(serializer.deserialize(CompressorFactory
- .getCompressor(raftSyncMessage.getCompressor()).decompress((byte[])raftSyncMessage.getBody()))));
+ .ifPresent(value -> raftSyncMessage.setBody(serializer.deserialize(CompressorFactory
+ .getCompressor(raftSyncMessage.getCompressor()).decompress((byte[])raftSyncMessage.getBody()))));
return raftSyncMessage;
- } catch (ClassNotFoundException | IOException e) {
+ } catch (Exception e) {
LOGGER.info("Failed to read raft synchronization log: {}", e.getMessage(), e);
+ if (e instanceof SeataRuntimeException) {
+ throw (SeataRuntimeException)e;
+ }
throw new RuntimeException(e);
}
}
diff --git a/server/src/test/java/org/apache/seata/server/raft/RaftSyncMessageTest.java b/server/src/test/java/org/apache/seata/server/raft/RaftSyncMessageTest.java
index 5510a19066..97b919516e 100644
--- a/server/src/test/java/org/apache/seata/server/raft/RaftSyncMessageTest.java
+++ b/server/src/test/java/org/apache/seata/server/raft/RaftSyncMessageTest.java
@@ -16,12 +16,15 @@
*/
package org.apache.seata.server.raft;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.apache.seata.common.exception.SeataRuntimeException;
import org.apache.seata.common.metadata.ClusterRole;
import org.apache.seata.common.metadata.Node;
import org.apache.seata.core.exception.TransactionException;
@@ -62,6 +65,19 @@ public class RaftSyncMessageTest {
public static void destroy(){
SessionHolder.destroy();
}
+
+ @Test
+ public void testSecurityMsgSerialize() throws IOException {
+ TestSecurity testSecurity = new TestSecurity();
+ byte[] bytes;
+ try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bos)) {
+ oos.writeObject(testSecurity);
+ bytes = bos.toByteArray();
+ }
+ Assertions.assertThrows(SeataRuntimeException.class,()->RaftSyncMessageSerializer.decode(bytes));
+ }
+
@Test
public void testMsgSerialize() throws IOException {
RaftSyncMessage raftSyncMessage = new RaftSyncMessage();
diff --git a/server/src/test/java/org/apache/seata/server/raft/TestSecurity.java b/server/src/test/java/org/apache/seata/server/raft/TestSecurity.java
new file mode 100644
index 0000000000..c8bd97c87c
--- /dev/null
+++ b/server/src/test/java/org/apache/seata/server/raft/TestSecurity.java
@@ -0,0 +1,32 @@
+/*
+ * 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.seata.server.raft;
+
+public class TestSecurity implements java.io.Serializable {
+
+ private static final long serialVersionUID = 543214259201495900L;
+
+ String a = "test";
+
+ public String getA() {
+ return a;
+ }
+
+ public void setA(String a) {
+ this.a = a;
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org
For additional commands, e-mail: notifications-help@seata.apache.org