diff --git a/build.gradle b/build.gradle index 65e72c0fb73..06186778971 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } ext { - grpcVersion = "1.83.0" + grpcVersion = "1.83.1" } allprojects { diff --git a/common/build.gradle b/common/build.gradle index 14d3eb4e637..4b36d067b70 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -8,7 +8,9 @@ sourceCompatibility = 1.8 dependencies { - api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.6' // https://github.com/FasterXML/jackson-databind/issues/3627 + // avoid x.y.z.w micro-patches, they may ship broken Gradle module metadata: + // https://github.com/FasterXML/jackson-databind/issues/3627 + api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.10' api "com.cedarsoftware:java-util:3.2.0" api group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.1' api group: 'commons-codec', name: 'commons-codec', version: '1.11' diff --git a/framework/src/main/java/org/tron/common/application/GrpcNettyMaxConcurrentStreamsLimiter.java b/framework/src/main/java/org/tron/common/application/GrpcNettyMaxConcurrentStreamsLimiter.java deleted file mode 100644 index cdd71ffee3c..00000000000 --- a/framework/src/main/java/org/tron/common/application/GrpcNettyMaxConcurrentStreamsLimiter.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * java-tron is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * java-tron is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with java-tron. If not, see . - */ - -package org.tron.common.application; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import io.grpc.netty.GrpcHttp2ConnectionHandler; -import io.grpc.netty.InternalProtocolNegotiator; -import io.grpc.netty.InternalProtocolNegotiators; -import io.grpc.netty.NettyServerBuilder; -import io.netty.channel.ChannelHandler; -import io.netty.util.AsciiString; - -/** Enforces the advertised HTTP/2 concurrent stream limit for grpc-netty servers. */ -final class GrpcNettyMaxConcurrentStreamsLimiter { - - private GrpcNettyMaxConcurrentStreamsLimiter() { - } - - static NettyServerBuilder configurePlaintext( - NettyServerBuilder builder, int maxConcurrentStreams) { - checkNotNull(builder, "builder"); - checkArgument(maxConcurrentStreams > 0, "maxConcurrentStreams must be positive"); - builder.maxConcurrentCallsPerConnection(maxConcurrentStreams); - // TODO: Remove this shim after https://github.com/grpc/grpc-java/issues/12930 is fixed. - return builder.protocolNegotiator(newPlaintextNegotiator(maxConcurrentStreams)); - } - - static InternalProtocolNegotiator.ProtocolNegotiator newPlaintextNegotiator( - int maxConcurrentStreams) { - checkArgument(maxConcurrentStreams > 0, "maxConcurrentStreams must be positive"); - return new EnforcingProtocolNegotiator( - InternalProtocolNegotiators.serverPlaintext(), maxConcurrentStreams); - } - - private static final class EnforcingProtocolNegotiator - implements InternalProtocolNegotiator.ProtocolNegotiator { - - private final InternalProtocolNegotiator.ProtocolNegotiator delegate; - private final int maxConcurrentStreams; - - private EnforcingProtocolNegotiator( - InternalProtocolNegotiator.ProtocolNegotiator delegate, int maxConcurrentStreams) { - this.delegate = checkNotNull(delegate, "delegate"); - this.maxConcurrentStreams = maxConcurrentStreams; - } - - @Override - public AsciiString scheme() { - return delegate.scheme(); - } - - @Override - public ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHandler) { - // grpc-java builds the connection directly, bypassing Netty's builder-side enforcement. - grpcHandler.connection().remote().maxActiveStreams(maxConcurrentStreams); - return delegate.newHandler(grpcHandler); - } - - @Override - public void close() { - delegate.close(); - } - } -} diff --git a/framework/src/main/java/org/tron/common/application/RpcService.java b/framework/src/main/java/org/tron/common/application/RpcService.java index 27fcc479f4e..c398b71ae41 100644 --- a/framework/src/main/java/org/tron/common/application/RpcService.java +++ b/framework/src/main/java/org/tron/common/application/RpcService.java @@ -100,9 +100,8 @@ protected NettyServerBuilder initServerBuilder() { serverBuilder = serverBuilder.executor(this.executorService); } // Set configs from config.conf or default value - serverBuilder = GrpcNettyMaxConcurrentStreamsLimiter.configurePlaintext( - serverBuilder, parameter.getMaxConcurrentCallsPerConnection()); serverBuilder + .maxConcurrentCallsPerConnection(parameter.getMaxConcurrentCallsPerConnection()) .flowControlWindow(parameter.getFlowControlWindow()) .maxConnectionIdle(parameter.getMaxConnectionIdleInMillis(), TimeUnit.MILLISECONDS) .maxConnectionAge(parameter.getMaxConnectionAgeInMillis(), TimeUnit.MILLISECONDS) diff --git a/framework/src/test/java/org/tron/common/application/GrpcNettyMaxConcurrentStreamsLimiterTest.java b/framework/src/test/java/org/tron/common/application/GrpcNettyMaxConcurrentStreamsLimiterTest.java deleted file mode 100644 index fc578ca7947..00000000000 --- a/framework/src/test/java/org/tron/common/application/GrpcNettyMaxConcurrentStreamsLimiterTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * java-tron is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * java-tron is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with java-tron. If not, see . - */ - -package org.tron.common.application; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThrows; - -import io.grpc.ChannelLogger; -import io.grpc.ChannelLogger.ChannelLogLevel; -import io.grpc.netty.GrpcHttp2ConnectionHandler; -import io.grpc.netty.InternalProtocolNegotiator; -import io.netty.channel.ChannelHandler; -import io.netty.handler.codec.http2.DefaultHttp2Connection; -import io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder; -import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder; -import io.netty.handler.codec.http2.DefaultHttp2FrameReader; -import io.netty.handler.codec.http2.DefaultHttp2FrameWriter; -import io.netty.handler.codec.http2.Http2Connection; -import io.netty.handler.codec.http2.Http2ConnectionDecoder; -import io.netty.handler.codec.http2.Http2ConnectionEncoder; -import io.netty.handler.codec.http2.Http2Error; -import io.netty.handler.codec.http2.Http2Exception; -import io.netty.handler.codec.http2.Http2FrameWriter; -import io.netty.handler.codec.http2.Http2Settings; -import org.junit.Test; - -public class GrpcNettyMaxConcurrentStreamsLimiterTest { - - private static final ChannelLogger NOOP_LOGGER = new ChannelLogger() { - @Override - public void log(ChannelLogLevel level, String message) { - } - - @Override - public void log(ChannelLogLevel level, String messageFormat, Object... args) { - } - }; - - @Test - public void shouldEnforceMaxStreamsBeforeSettingsAck() throws Exception { - Http2Connection connection = new DefaultHttp2Connection(true); - GrpcHttp2ConnectionHandler grpcHandler = newGrpcHandler(connection); - InternalProtocolNegotiator.ProtocolNegotiator negotiator = - GrpcNettyMaxConcurrentStreamsLimiter.newPlaintextNegotiator(2); - - ChannelHandler negotiationHandler = negotiator.newHandler(grpcHandler); - - assertNotNull(negotiationHandler); - assertEquals(2, connection.remote().maxActiveStreams()); - connection.remote().createStream(1, true); - connection.remote().createStream(3, true); - Http2Exception exception = assertThrows( - Http2Exception.class, () -> connection.remote().createStream(5, true)); - assertEquals(Http2Error.REFUSED_STREAM, exception.error()); - negotiator.close(); - } - - @Test - public void shouldIgnoreClientMaxHeaderListSizeOnServer() throws Exception { - Http2Connection connection = new DefaultHttp2Connection(true); - Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter(); - Http2ConnectionEncoder encoder = - new DefaultHttp2ConnectionEncoder(connection, frameWriter); - long originalMaxHeaderListSize = - encoder.configuration().headersConfiguration().maxHeaderListSize(); - - encoder.remoteSettings(new Http2Settings().maxHeaderListSize(1)); - - assertEquals(originalMaxHeaderListSize, - encoder.configuration().headersConfiguration().maxHeaderListSize()); - encoder.close(); - } - - @Test - public void shouldRejectNonPositiveStreamLimit() { - IllegalArgumentException zeroLimitException = assertThrows(IllegalArgumentException.class, - () -> GrpcNettyMaxConcurrentStreamsLimiter.newPlaintextNegotiator(0)); - assertEquals("maxConcurrentStreams must be positive", zeroLimitException.getMessage()); - IllegalArgumentException negativeLimitException = assertThrows(IllegalArgumentException.class, - () -> GrpcNettyMaxConcurrentStreamsLimiter.newPlaintextNegotiator(-1)); - assertEquals("maxConcurrentStreams must be positive", negativeLimitException.getMessage()); - } - - private static GrpcHttp2ConnectionHandler newGrpcHandler(Http2Connection connection) { - Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter(); - Http2ConnectionEncoder encoder = - new DefaultHttp2ConnectionEncoder(connection, frameWriter); - Http2ConnectionDecoder decoder = new DefaultHttp2ConnectionDecoder( - connection, encoder, new DefaultHttp2FrameReader()); - return new GrpcHttp2ConnectionHandler( - null, decoder, encoder, new Http2Settings(), NOOP_LOGGER) { - }; - } -} diff --git a/framework/src/test/java/org/tron/common/application/NettyHttp2HeaderSecurityTest.java b/framework/src/test/java/org/tron/common/application/NettyHttp2HeaderSecurityTest.java new file mode 100644 index 00000000000..6a4f4330f04 --- /dev/null +++ b/framework/src/test/java/org/tron/common/application/NettyHttp2HeaderSecurityTest.java @@ -0,0 +1,53 @@ +/* + * java-tron is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * java-tron is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with java-tron. If not, see . + */ + +package org.tron.common.application; + +import static org.junit.Assert.assertEquals; + +import io.netty.handler.codec.http2.DefaultHttp2Connection; +import io.netty.handler.codec.http2.DefaultHttp2ConnectionEncoder; +import io.netty.handler.codec.http2.DefaultHttp2FrameWriter; +import io.netty.handler.codec.http2.Http2Connection; +import io.netty.handler.codec.http2.Http2ConnectionEncoder; +import io.netty.handler.codec.http2.Http2FrameWriter; +import io.netty.handler.codec.http2.Http2Settings; +import org.junit.Test; + +/** Guards the netty HTTP/2 header-size behaviour the gRPC server relies on. */ +public class NettyHttp2HeaderSecurityTest { + + /** + * CVE-2026-50560: SETTINGS_MAX_HEADER_LIST_SIZE tells the server what the client is willing to + * receive, so it must not shrink the server encoder's own limit. Otherwise a hostile client can + * advertise a tiny value and make every response-header write throw, which is a Rapid-Reset-like + * denial of service. Netty enforced the client value before 4.1.135.Final / 4.2.15.Final. + */ + @Test + public void shouldIgnoreClientMaxHeaderListSizeOnServer() throws Exception { + Http2Connection connection = new DefaultHttp2Connection(true); + Http2FrameWriter frameWriter = new DefaultHttp2FrameWriter(); + Http2ConnectionEncoder encoder = + new DefaultHttp2ConnectionEncoder(connection, frameWriter); + long originalMaxHeaderListSize = + encoder.configuration().headersConfiguration().maxHeaderListSize(); + + encoder.remoteSettings(new Http2Settings().maxHeaderListSize(1)); + + assertEquals(originalMaxHeaderListSize, + encoder.configuration().headersConfiguration().maxHeaderListSize()); + encoder.close(); + } +} diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 6a3e641d5d6..08c7f6d34b9 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -189,9 +189,9 @@ - - - + + + @@ -199,9 +199,9 @@ - - - + + + @@ -219,15 +219,15 @@ - - - + + + - - + + - - + + @@ -235,15 +235,15 @@ - - - + + + - - + + - - + + @@ -251,15 +251,15 @@ - - - + + + - - + + - - + + @@ -1171,76 +1171,76 @@ - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + @@ -1251,18 +1251,18 @@ - - - + + + - - + + - - + + - - + +