You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by do...@apache.org on 2022/04/11 00:45:04 UTC
[spark] branch branch-3.3 updated: [SPARK-38830][CORE] Warn on corrupted block messages
This is an automated email from the ASF dual-hosted git repository.
dongjoon pushed a commit to branch branch-3.3
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/branch-3.3 by this push:
new 82581684c64 [SPARK-38830][CORE] Warn on corrupted block messages
82581684c64 is described below
commit 82581684c64dcd388d757ebde8ec0b9eb2a30816
Author: Dongjoon Hyun <do...@apache.org>
AuthorDate: Sun Apr 10 17:44:39 2022 -0700
[SPARK-38830][CORE] Warn on corrupted block messages
### What changes were proposed in this pull request?
This PR aims to warn when `NettyBlockRpcServer` received a corrupted block RPC message or under attack.
- `IllegalArgumentException`: When the type is unknown/invalid when decoding. This fails at Spark layer.
- `NegativeArraySizeException`: When the size read is negative. This fails at Spark layer during buffer creation.
- `IndexOutOfBoundsException`: When the data field isn't matched with the size. This fails at Netty later.
### Why are the changes needed?
When the RPC messages are corrupted or the servers are under attack, Spark shows `IndexOutOfBoundsException` due to the failure from `Decoder`. Instead of `Exception`, we had better ignore the message with a directional warning message.
```
java.lang.IndexOutOfBoundsException:
readerIndex(5) + length(602416) exceeds writerIndex(172):
UnpooledUnsafeDirectByteBuf(ridx: 5, widx: 172, cap: 172/172)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1477)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes(AbstractByteBuf.java:1463)
at io.netty.buffer.UnpooledDirectByteBuf.readBytes(UnpooledDirectByteBuf.java:316)
at io.netty.buffer.AbstractByteBuf.readBytes(AbstractByteBuf.java:904)
at org.apache.spark.network.protocol.Encoders$Strings.decode(Encoders.java:45)
at org.apache.spark.network.shuffle.protocol.UploadBlock.decode(UploadBlock.java:112)
at org.apache.spark.network.shuffle.protocol.BlockTransferMessage$Decoder.fromByteBuffer(BlockTransferMessage.java:71)
at org.apache.spark.network.netty.NettyBlockRpcServer.receive(NettyBlockRpcServer.scala:53)
at org.apache.spark.network.server.TransportRequestHandler.processRpcRequest(TransportRequestHandler.java:161)
at org.apache.spark.network.server.TransportRequestHandler.handle(TransportRequestHandler.java:109)
at org.apache.spark.network.server.TransportChannelHandler.channelRead0(TransportChannelHandler.java:140)
at org.apache.spark.network.server.TransportChannelHandler.channelRead0(TransportChannelHandler.java:53)
```
### Does this PR introduce _any_ user-facing change?
Yes, but this clarify the log messages from exceptions, `IndexOutOfBoundsException`.
### How was this patch tested?
Pass the CIs with newly added test suite.
Closes #36116 from dongjoon-hyun/SPARK-38830.
Authored-by: Dongjoon Hyun <do...@apache.org>
Signed-off-by: Dongjoon Hyun <do...@apache.org>
(cherry picked from commit 8ac06474f8cfa8e5619f817aaeea29a77ec8a2a4)
Signed-off-by: Dongjoon Hyun <do...@apache.org>
---
.../spark/network/netty/NettyBlockRpcServer.scala | 18 ++++++-
.../network/netty/NettyBlockRpcServerSuite.scala | 59 ++++++++++++++++++++++
2 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/core/src/main/scala/org/apache/spark/network/netty/NettyBlockRpcServer.scala b/core/src/main/scala/org/apache/spark/network/netty/NettyBlockRpcServer.scala
index 81c878d17c6..f2a1fe49fcf 100644
--- a/core/src/main/scala/org/apache/spark/network/netty/NettyBlockRpcServer.scala
+++ b/core/src/main/scala/org/apache/spark/network/netty/NettyBlockRpcServer.scala
@@ -50,7 +50,23 @@ class NettyBlockRpcServer(
client: TransportClient,
rpcMessage: ByteBuffer,
responseContext: RpcResponseCallback): Unit = {
- val message = BlockTransferMessage.Decoder.fromByteBuffer(rpcMessage)
+ val message = try {
+ BlockTransferMessage.Decoder.fromByteBuffer(rpcMessage)
+ } catch {
+ case e: IllegalArgumentException if e.getMessage.startsWith("Unknown message type") =>
+ logWarning(s"This could be a corrupted RPC message (capacity: ${rpcMessage.capacity()}) " +
+ s"from ${client.getSocketAddress}. Please use `spark.authenticate.*` configurations " +
+ "in case of security incidents.")
+ throw e
+
+ case _: IndexOutOfBoundsException | _: NegativeArraySizeException =>
+ // Netty may throw non-'IOException's for corrupted buffers. In this case,
+ // we ignore the entire message with warnings because we cannot trust any contents.
+ logWarning(s"Ignored a corrupted RPC message (capacity: ${rpcMessage.capacity()}) " +
+ s"from ${client.getSocketAddress}. Please use `spark.authenticate.*` configurations " +
+ "in case of security incidents.")
+ return
+ }
logTrace(s"Received request: $message")
message match {
diff --git a/core/src/test/scala/org/apache/spark/network/netty/NettyBlockRpcServerSuite.scala b/core/src/test/scala/org/apache/spark/network/netty/NettyBlockRpcServerSuite.scala
new file mode 100644
index 00000000000..54e83e7bda5
--- /dev/null
+++ b/core/src/test/scala/org/apache/spark/network/netty/NettyBlockRpcServerSuite.scala
@@ -0,0 +1,59 @@
+/*
+ * 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.spark.network.netty
+
+import java.nio.ByteBuffer
+
+import org.mockito.Mockito.mock
+
+import org.apache.spark.{SparkConf, SparkFunSuite}
+import org.apache.spark.network.client.TransportClient
+import org.apache.spark.serializer.JavaSerializer
+
+class NettyBlockRpcServerSuite extends SparkFunSuite {
+
+ test("SPARK-38830: Rethrow IllegalArgumentException due to `Unknown message type`") {
+ val serializer = new JavaSerializer(new SparkConf)
+ val server = new NettyBlockRpcServer("enhanced-rpc-server", serializer, null)
+ val bytes = Array[Byte](100.toByte)
+ val message = ByteBuffer.wrap(bytes)
+ val client = mock(classOf[TransportClient])
+ val m = intercept[IllegalArgumentException] {
+ server.receive(client, message)
+ }.getMessage
+ assert(m.startsWith("Unknown message type: 100"))
+ }
+
+ test("SPARK-38830: Warn and ignore NegativeArraySizeException due to the corruption") {
+ val serializer = new JavaSerializer(new SparkConf)
+ val server = new NettyBlockRpcServer("enhanced-rpc-server", serializer, null)
+ val bytes = Array[Byte](0.toByte, 0xFF.toByte, 0xFF.toByte, 0xFF.toByte, 0xFF.toByte)
+ val message = ByteBuffer.wrap(bytes)
+ val client = mock(classOf[TransportClient])
+ server.receive(client, message)
+ }
+
+ test("SPARK-38830: Warn and ignore IndexOutOfBoundsException due to the corruption") {
+ val serializer = new JavaSerializer(new SparkConf)
+ val server = new NettyBlockRpcServer("enhanced-rpc-server", serializer, null)
+ val bytes = Array[Byte](1.toByte)
+ val message = ByteBuffer.wrap(bytes)
+ val client = mock(classOf[TransportClient])
+ server.receive(client, message)
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org