This is an automated email from the ASF dual-hosted git repository.
steveloughran pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/hadoop.git
The following commit(s) were added to refs/heads/trunk by this push:
new 4b224cdedcf HADOOP-19864 Followup: rejection of unregistered
protocols. (#8470)
4b224cdedcf is described below
commit 4b224cdedcf585f95305dc04379ab9a69c2b951b
Author: Steve Loughran <[email protected]>
AuthorDate: Sat May 9 18:18:13 2026 +0100
HADOOP-19864 Followup: rejection of unregistered protocols. (#8470)
Server will immediately reject any protocols for which no
handler is registered.
---------
Contributed by Steve Loughran
Co-authored-by: Cheng Pan <[email protected]>
Contains content written by github copilot
---
.../src/main/java/org/apache/hadoop/ipc/RPC.java | 17 +++++++++--
.../main/java/org/apache/hadoop/ipc/Server.java | 34 +++++++++++++++-------
.../test/java/org/apache/hadoop/ipc/TestRPC.java | 25 ++++++++++++++++
3 files changed, 63 insertions(+), 13 deletions(-)
diff --git
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/RPC.java
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/RPC.java
index 4209827172f..31723219284 100644
---
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/RPC.java
+++
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/RPC.java
@@ -1098,9 +1098,22 @@ Map<ProtoNameVer, ProtoClassProtoImpl>
getProtocolImplMap(RPC.RpcKind rpcKind) {
new HashMap<ProtoNameVer, ProtoClassProtoImpl>(10));
}
}
- return protocolImplMapArray.get(rpcKind.ordinal());
+ return protocolImplMapArray.get(rpcKind.ordinal());
}
-
+
+ /**
+ * Returns {@code true} only if at least one protocol has been registered
+ * on this server instance for the given {@link RPC.RpcKind}.
+ * Used to reject incoming requests for unsupported RPC kinds before any
+ * deserialization of the request payload takes place.
+ * @param rpcKind the RPC kind from the incoming request header.
+ * @return {@code true} if at least one protocol is registered for this
kind.
+ */
+ boolean hasRegisteredProtocols(RPC.RpcKind rpcKind) {
+ Map<ProtoNameVer, ProtoClassProtoImpl> implMap =
getProtocolImplMap(rpcKind);
+ return implMap != null && !implMap.isEmpty();
+ }
+
// Register protocol and its impl for rpc calls
void registerProtocolAndImpl(RpcKind rpcKind, Class<?> protocolClass,
Object protocolImpl) {
diff --git
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java
index 48c8dec61a2..b6979be0413 100644
---
a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java
+++
b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java
@@ -2946,15 +2946,27 @@ private void processRpcRequest(RpcRequestHeaderProto
header,
throw new FatalRpcServerException(
RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER, err);
}
- Class<? extends Writable> rpcRequestClass =
+ // Reject requests for RPC kinds with no registered protocols on this
+ // server instance. This prevents deserialization of untrusted payloads
+ // for unsupported kinds. See HADOOP-19864.
+ if (Server.this instanceof RPC.Server server) {
+ final RPC.RpcKind kind = ProtoUtil.convert(header.getRpcKind());
+ if (!server.hasRegisteredProtocols(kind)) {
+ final String err = "No protocols registered on this server for
RpcKind "
+ + header.getRpcKind()
+ + ". Rejecting request without deserialization.";
+ LOG.info("{} Client: {}", err, getHostAddress());
+ throw new FatalRpcServerException(
+ RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER, err);
+ }
+ }
+ Class<? extends Writable> rpcRequestClass =
getRpcRequestWrapper(header.getRpcKind());
if (rpcRequestClass == null) {
- LOG.warn("Unknown rpc kind " + header.getRpcKind() +
- " from client " + getHostAddress());
- final String err = "Unknown rpc kind in rpc header" +
- header.getRpcKind();
+ LOG.warn("Unknown rpc kind {} from client {}", header.getRpcKind(),
getHostAddress());
throw new FatalRpcServerException(
- RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER, err);
+ RpcErrorCodeProto.FATAL_INVALID_RPC_HEADER,
+ "Unknown rpc kind in rpc header " + header.getRpcKind());
}
Writable rpcRequest;
try { //Read the rpc request
@@ -2962,12 +2974,12 @@ private void processRpcRequest(RpcRequestHeaderProto
header,
} catch (RpcServerException rse) { // lets tests inject failures.
throw rse;
} catch (Throwable t) { // includes runtime exception from newInstance
- LOG.warn("Unable to read call parameters for client " +
- getHostAddress() + "on connection protocol " +
- this.protocolName + " for rpcKind " + header.getRpcKind(), t);
- String err = "IPC server unable to read call parameters: "+
t.getMessage();
+ LOG.warn(
+ "Unable to read call parameters for client {} on connection
protocol {} for rpcKind {}",
+ getHostAddress(), this.protocolName, header.getRpcKind(), t);
throw new FatalRpcServerException(
- RpcErrorCodeProto.FATAL_DESERIALIZING_REQUEST, err);
+ RpcErrorCodeProto.FATAL_DESERIALIZING_REQUEST,
+ "IPC server unable to read call parameters: " + t.getMessage());
}
Span span = null;
diff --git
a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRPC.java
b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRPC.java
index 6cb4697ddaa..e24833a161f 100644
---
a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRPC.java
+++
b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestRPC.java
@@ -2116,6 +2116,31 @@ public void testNumTotalRequestsMetrics() throws
Exception {
}
+ /**
+ * Test that a Protobuf-only RPC server rejects requests for RpcKinds
+ * that have no registered protocols, without deserializing the payload.
+ */
+ @Test
+ @Timeout(value = 30)
+ public void testUnregisteredRpcKindRejectedWithoutDeserialization()
+ throws Exception {
+ // Standard test server: only RPC_PROTOCOL_BUFFER protocols are registered.
+ RPC.Server server = setupTestServer(conf, 1);
+ try {
+ // RPC_PROTOCOL_BUFFER has registered protocols — must be accepted.
+
assertThat(server.hasRegisteredProtocols(RPC.RpcKind.RPC_PROTOCOL_BUFFER))
+ .as("RPC_PROTOCOL_BUFFER should have registered protocols")
+ .isTrue();
+
+ // RPC_BUILTIN has no protocols registered on this server — must be
rejected.
+ assertThat(server.hasRegisteredProtocols(RPC.RpcKind.RPC_BUILTIN))
+ .as("RPC_BUILTIN should have no registered protocols on a
Protobuf-only server")
+ .isFalse();
+ } finally {
+ server.stop();
+ }
+ }
+
public static void main(String[] args) throws Exception {
new TestRPC().testCallsInternal(conf);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]