Add whitelist entry for SSLEngineImpl.wrap to BlockHound configuration (#10844)

Motivation:

Internally SSLEngineImpl.wrap(...) may call FileInputStream.read(...).
This will cause the error below when BlockHound is enabled
reactor.blockhound.BlockingOperationError: Blocking call! java.io.FileInputStream#readBytes
	at java.io.FileInputStream.readBytes(FileInputStream.java)
	at java.io.FileInputStream.read(FileInputStream.java:255)

Modifications:

- Add whitelist entry to BlockHound configuration
- Add test

Result:

Fixes #10837
This commit is contained in:
Violeta Georgieva 2020-12-07 09:06:21 +02:00 committed by GitHub
parent 44f85bba5f
commit 8a7c580bf6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 0 deletions

View File

@ -111,6 +111,10 @@ class Hidden {
"sun.security.ssl.SSLEngineImpl", "sun.security.ssl.SSLEngineImpl",
"unwrap"); "unwrap");
builder.allowBlockingCallsInside(
"sun.security.ssl.SSLEngineImpl",
"wrap");
builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() { builder.nonBlockingThreadPredicate(new Function<Predicate<Thread>, Predicate<Thread>>() {
@Override @Override
public Predicate<Thread> apply(final Predicate<Thread> p) { public Predicate<Thread> apply(final Predicate<Thread> p) {

View File

@ -20,6 +20,7 @@ import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
@ -63,9 +64,13 @@ import java.util.concurrent.Future;
import java.util.concurrent.FutureTask; import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import static io.netty.buffer.Unpooled.wrappedBuffer;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
@ -238,6 +243,77 @@ public class NettyBlockHoundIntegrationTest {
testTrustManagerVerify("TLSv1.3"); testTrustManagerVerify("TLSv1.3");
} }
@Test
public void testSslHandlerWrapAllowsBlockingCalls() throws Exception {
final SslContext sslClientCtx =
SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.sslProvider(SslProvider.JDK)
.build();
final SslHandler sslHandler = sslClientCtx.newHandler(UnpooledByteBufAllocator.DEFAULT);
final EventLoopGroup group = new NioEventLoopGroup();
final CountDownLatch activeLatch = new CountDownLatch(1);
final AtomicReference<Throwable> error = new AtomicReference<>();
Channel sc = null;
Channel cc = null;
try {
sc = new ServerBootstrap()
.group(group)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInboundHandlerAdapter())
.bind(new InetSocketAddress(0))
.syncUninterruptibly()
.channel();
cc = new Bootstrap()
.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) {
ch.pipeline().addLast(sslHandler);
ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelActive(ChannelHandlerContext ctx) {
activeLatch.countDown();
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (evt instanceof SslHandshakeCompletionEvent &&
((SslHandshakeCompletionEvent) evt).cause() != null) {
Throwable cause = ((SslHandshakeCompletionEvent) evt).cause();
cause.printStackTrace();
error.set(cause);
}
ctx.fireUserEventTriggered(evt);
}
});
}
})
.connect(sc.localAddress())
.addListener((ChannelFutureListener) future ->
future.channel().writeAndFlush(wrappedBuffer(new byte [] { 1, 2, 3, 4 })))
.syncUninterruptibly()
.channel();
assertTrue(activeLatch.await(5, TimeUnit.SECONDS));
assertNull(error.get());
} finally {
if (cc != null) {
cc.close().syncUninterruptibly();
}
if (sc != null) {
sc.close().syncUninterruptibly();
}
group.shutdownGracefully();
ReferenceCountUtil.release(sslClientCtx);
}
}
private static void testTrustManagerVerify(String tlsVersion) throws Exception { private static void testTrustManagerVerify(String tlsVersion) throws Exception {
final SslContext sslClientCtx = final SslContext sslClientCtx =
SslContextBuilder.forClient() SslContextBuilder.forClient()