From f4270f99142ad784b9f7ea9b5e5939119d16b35d Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Fri, 13 Jan 2017 14:27:09 -0600 Subject: [PATCH] Wrap netty accept/connect ops with doPrivileged (#22572) This is related to #22116. netty channels require socket `connect` and `accept` privileges. Netty does not currently wrap these operations with `doPrivileged` blocks. These changes extend the netty channels and wrap calls to the relevant super methods in doPrivileged blocks. --- .../netty4/Netty4HttpServerTransport.java | 8 +-- .../transport/netty4/Netty4Transport.java | 16 +++--- .../PrivilegedNioServerSocketChannel.java | 50 +++++++++++++++++ .../channel/PrivilegedNioSocketChannel.java | 50 +++++++++++++++++ .../PrivilegedOioServerSocketChannel.java | 50 +++++++++++++++++ .../channel/PrivilegedOioSocketChannel.java | 54 +++++++++++++++++++ .../http/netty4/Netty4HttpClient.java | 4 +- 7 files changed, 218 insertions(+), 14 deletions(-) create mode 100644 modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedNioServerSocketChannel.java create mode 100644 modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedNioSocketChannel.java create mode 100644 modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedOioServerSocketChannel.java create mode 100644 modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedOioSocketChannel.java diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java b/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java index 00b86d813ad..c6c2899e4b3 100644 --- a/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpServerTransport.java @@ -33,8 +33,6 @@ import io.netty.channel.FixedRecvByteBufAllocator; import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.oio.OioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.channel.socket.oio.OioServerSocketChannel; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.http.HttpContentCompressor; import io.netty.handler.codec.http.HttpContentDecompressor; @@ -80,6 +78,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.BindTransportException; import org.elasticsearch.transport.netty4.Netty4OpenChannelsHandler; import org.elasticsearch.transport.netty4.Netty4Utils; +import org.elasticsearch.transport.netty4.channel.PrivilegedNioServerSocketChannel; +import org.elasticsearch.transport.netty4.channel.PrivilegedOioServerSocketChannel; import java.io.IOException; import java.net.InetAddress; @@ -301,11 +301,11 @@ public class Netty4HttpServerTransport extends AbstractLifecycleComponent implem if (blockingServer) { serverBootstrap.group(new OioEventLoopGroup(workerCount, daemonThreadFactory(settings, HTTP_SERVER_WORKER_THREAD_NAME_PREFIX))); - serverBootstrap.channel(OioServerSocketChannel.class); + serverBootstrap.channel(PrivilegedOioServerSocketChannel.class); } else { serverBootstrap.group(new NioEventLoopGroup(workerCount, daemonThreadFactory(settings, HTTP_SERVER_WORKER_THREAD_NAME_PREFIX))); - serverBootstrap.channel(NioServerSocketChannel.class); + serverBootstrap.channel(PrivilegedNioServerSocketChannel.class); } serverBootstrap.childHandler(configureServerChannelHandler()); diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java index d92313fb0bb..7dd0a65dfc4 100644 --- a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/Netty4Transport.java @@ -33,10 +33,6 @@ import io.netty.channel.FixedRecvByteBufAllocator; import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.oio.OioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; -import io.netty.channel.socket.oio.OioServerSocketChannel; -import io.netty.channel.socket.oio.OioSocketChannel; import io.netty.util.concurrent.Future; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; @@ -67,6 +63,10 @@ import org.elasticsearch.transport.TcpTransport; import org.elasticsearch.transport.TransportRequestOptions; import org.elasticsearch.transport.TransportServiceAdapter; import org.elasticsearch.transport.TransportSettings; +import org.elasticsearch.transport.netty4.channel.PrivilegedNioServerSocketChannel; +import org.elasticsearch.transport.netty4.channel.PrivilegedNioSocketChannel; +import org.elasticsearch.transport.netty4.channel.PrivilegedOioServerSocketChannel; +import org.elasticsearch.transport.netty4.channel.PrivilegedOioSocketChannel; import java.io.IOException; import java.net.InetSocketAddress; @@ -195,10 +195,10 @@ public class Netty4Transport extends TcpTransport { final Bootstrap bootstrap = new Bootstrap(); if (TCP_BLOCKING_CLIENT.get(settings)) { bootstrap.group(new OioEventLoopGroup(1, daemonThreadFactory(settings, TRANSPORT_CLIENT_WORKER_THREAD_NAME_PREFIX))); - bootstrap.channel(OioSocketChannel.class); + bootstrap.channel(PrivilegedOioSocketChannel.class); } else { bootstrap.group(new NioEventLoopGroup(workerCount, daemonThreadFactory(settings, TRANSPORT_CLIENT_BOSS_THREAD_NAME_PREFIX))); - bootstrap.channel(NioSocketChannel.class); + bootstrap.channel(PrivilegedNioSocketChannel.class); } bootstrap.handler(getClientChannelInitializer()); @@ -284,10 +284,10 @@ public class Netty4Transport extends TcpTransport { if (TCP_BLOCKING_SERVER.get(settings)) { serverBootstrap.group(new OioEventLoopGroup(workerCount, workerFactory)); - serverBootstrap.channel(OioServerSocketChannel.class); + serverBootstrap.channel(PrivilegedOioServerSocketChannel.class); } else { serverBootstrap.group(new NioEventLoopGroup(workerCount, workerFactory)); - serverBootstrap.channel(NioServerSocketChannel.class); + serverBootstrap.channel(PrivilegedNioServerSocketChannel.class); } serverBootstrap.childHandler(getServerChannelInitializer(name, settings)); diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedNioServerSocketChannel.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedNioServerSocketChannel.java new file mode 100644 index 00000000000..075a41f157b --- /dev/null +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedNioServerSocketChannel.java @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.transport.netty4.channel; + +import io.netty.channel.socket.nio.NioServerSocketChannel; +import org.elasticsearch.SpecialPermission; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.List; + +/** + * Wraps netty calls to {@link java.nio.channels.ServerSocketChannel#accept()} in + * {@link AccessController#doPrivileged(PrivilegedAction)} blocks. This is necessary to limit + * {@link java.net.SocketPermission} to the transport module. + */ +public class PrivilegedNioServerSocketChannel extends NioServerSocketChannel { + + @Override + protected int doReadMessages(List buf) throws Exception { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new SpecialPermission()); + } + try { + return AccessController.doPrivileged((PrivilegedExceptionAction) () -> super.doReadMessages(buf)); + } catch (PrivilegedActionException e) { + throw (Exception) e.getCause(); + } + } +} diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedNioSocketChannel.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedNioSocketChannel.java new file mode 100644 index 00000000000..daa6a2baec5 --- /dev/null +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedNioSocketChannel.java @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.transport.netty4.channel; + +import io.netty.channel.socket.nio.NioSocketChannel; +import org.elasticsearch.SpecialPermission; + +import java.net.SocketAddress; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * Wraps netty calls to {@link java.nio.channels.SocketChannel#connect(SocketAddress)} in + * {@link AccessController#doPrivileged(PrivilegedAction)} blocks. This is necessary to limit + * {@link java.net.SocketPermission} to the transport module. + */ +public class PrivilegedNioSocketChannel extends NioSocketChannel { + + @Override + protected boolean doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new SpecialPermission()); + } + try { + return AccessController.doPrivileged((PrivilegedExceptionAction) () -> super.doConnect(remoteAddress, localAddress)); + } catch (PrivilegedActionException e) { + throw (Exception) e.getCause(); + } + } +} diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedOioServerSocketChannel.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedOioServerSocketChannel.java new file mode 100644 index 00000000000..c0643adfb16 --- /dev/null +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedOioServerSocketChannel.java @@ -0,0 +1,50 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.transport.netty4.channel; + +import io.netty.channel.socket.oio.OioServerSocketChannel; +import org.elasticsearch.SpecialPermission; + +import java.net.ServerSocket; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.List; + +/** + * Wraps netty calls to {@link ServerSocket#accept()} in {@link AccessController#doPrivileged(PrivilegedAction)} blocks. + * This is necessary to limit {@link java.net.SocketPermission} to the transport module. + */ +public class PrivilegedOioServerSocketChannel extends OioServerSocketChannel { + + @Override + protected int doReadMessages(List buf) throws Exception { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new SpecialPermission()); + } + try { + return AccessController.doPrivileged((PrivilegedExceptionAction) () -> super.doReadMessages(buf)); + } catch (PrivilegedActionException e) { + throw (Exception) e.getCause(); + } + } +} diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedOioSocketChannel.java b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedOioSocketChannel.java new file mode 100644 index 00000000000..e5a169e7a24 --- /dev/null +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/transport/netty4/channel/PrivilegedOioSocketChannel.java @@ -0,0 +1,54 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.transport.netty4.channel; + +import io.netty.channel.socket.oio.OioSocketChannel; +import org.elasticsearch.SpecialPermission; + +import java.net.SocketAddress; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +/** + * Wraps netty calls to {@link java.net.Socket#connect(SocketAddress)} in + * {@link AccessController#doPrivileged(PrivilegedAction)} blocks. This is necessary to limit + * {@link java.net.SocketPermission} to the transport module. + */ +public class PrivilegedOioSocketChannel extends OioSocketChannel { + + @Override + protected void doConnect(SocketAddress remoteAddress, SocketAddress localAddress) throws Exception { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new SpecialPermission()); + } + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + super.doConnect(remoteAddress, localAddress); + return null; + }); + } catch (PrivilegedActionException e) { + throw (Exception) e.getCause(); + } + super.doConnect(remoteAddress, localAddress); + } +} diff --git a/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpClient.java b/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpClient.java index ad1fedc49b0..959a4d7c9f0 100644 --- a/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpClient.java +++ b/modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpClient.java @@ -28,7 +28,6 @@ import io.netty.channel.ChannelInitializer; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; -import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; @@ -44,6 +43,7 @@ import io.netty.handler.codec.http.HttpVersion; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeValue; +import org.elasticsearch.transport.netty4.channel.PrivilegedNioSocketChannel; import java.io.Closeable; import java.net.SocketAddress; @@ -82,7 +82,7 @@ class Netty4HttpClient implements Closeable { private final Bootstrap clientBootstrap; Netty4HttpClient() { - clientBootstrap = new Bootstrap().channel(NioSocketChannel.class).group(new NioEventLoopGroup()); + clientBootstrap = new Bootstrap().channel(PrivilegedNioSocketChannel.class).group(new NioEventLoopGroup()); } public Collection get(SocketAddress remoteAddress, String... uris) throws InterruptedException {