Fix event loop hang in SniHandler (#9933)

Motivation

A bug was introduced in #9806 which looks likely to be the cause of
#9919. SniHandler will enter an infinite loop if an SSL record is
received with SSL major version byte != 3 (i.e. something other than TLS
or SSL3.0)

Modifications

- Follow default path as intended  for majorVersion != 3 in
AbstractSniHandler#decode(...)
- Add unit test to reproduce the hang

Result

Fixes #9919
This commit is contained in:
Nick Hill 2020-01-09 23:49:09 -08:00 committed by Norman Maurer
parent b82258b72f
commit 41c47b41bf
2 changed files with 40 additions and 2 deletions

View File

@ -153,8 +153,9 @@ public abstract class AbstractSniHandler<T> extends ByteToMessageDecoder impleme
select(ctx, extractSniHostname(handshakeBuffer, 0, handshakeLength)); select(ctx, extractSniHostname(handshakeBuffer, 0, handshakeLength));
return; return;
} }
break;
} }
break; // fall-through
default: default:
// not tls, ssl or application data, do not try sni // not tls, ssl or application data, do not try sni
select(ctx, null); select(ctx, null);

View File

@ -320,7 +320,7 @@ public class SniHandlerTest {
ch.writeInbound(Unpooled.wrappedBuffer(message)); ch.writeInbound(Unpooled.wrappedBuffer(message));
// TODO(scott): This should fail because the engine should reject zero length records during handshake. // TODO(scott): This should fail because the engine should reject zero length records during handshake.
// See https://github.com/netty/netty/issues/6348. // See https://github.com/netty/netty/issues/6348.
// fail(); fail();
} catch (Exception e) { } catch (Exception e) {
// expected // expected
} }
@ -344,6 +344,43 @@ public class SniHandlerTest {
} }
} }
@Test(timeout = 10000)
public void testMajorVersionNot3() throws Exception {
SslContext nettyContext = makeSslContext(provider, false);
try {
DomainNameMapping<SslContext> mapping = new DomainNameMappingBuilder<SslContext>(nettyContext).build();
SniHandler handler = new SniHandler(mapping);
EmbeddedChannel ch = new EmbeddedChannel(handler);
// invalid
byte[] message = {22, 2, 0, 0, 0};
try {
// Push the handshake message.
ch.writeInbound(Unpooled.wrappedBuffer(message));
fail();
} catch (Exception e) {
// expected
}
ch.close();
// When the channel is closed the SslHandler will write an empty buffer to the channel.
ByteBuf buf = ch.readOutbound();
if (buf != null) {
assertFalse(buf.isReadable());
buf.release();
}
assertThat(ch.finish(), is(false));
assertThat(handler.hostname(), nullValue());
assertThat(handler.sslContext(), is(nettyContext));
} finally {
releaseAll(nettyContext);
}
}
@Test @Test
public void testSniWithApnHandler() throws Exception { public void testSniWithApnHandler() throws Exception {
SslContext nettyContext = makeSslContext(provider, true); SslContext nettyContext = makeSslContext(provider, true);