Skip to content

Commit d3a1d9b

Browse files
authored
Add "always denied" network access checks (#119867)
1 parent 80729f9 commit d3a1d9b

File tree

4 files changed

+166
-9
lines changed

4 files changed

+166
-9
lines changed

libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@
1515
import java.net.ContentHandlerFactory;
1616
import java.net.DatagramSocketImplFactory;
1717
import java.net.FileNameMap;
18+
import java.net.ProxySelector;
19+
import java.net.ResponseCache;
1820
import java.net.SocketImplFactory;
1921
import java.net.URL;
22+
import java.net.URLStreamHandler;
2023
import java.net.URLStreamHandlerFactory;
2124
import java.util.List;
2225

2326
import javax.net.ssl.HostnameVerifier;
2427
import javax.net.ssl.HttpsURLConnection;
2528
import javax.net.ssl.SSLContext;
29+
import javax.net.ssl.SSLSession;
2630
import javax.net.ssl.SSLSocketFactory;
2731

2832
@SuppressWarnings("unused") // Called from instrumentation code inserted by the Entitlements agent
@@ -167,4 +171,22 @@ public interface EntitlementChecker {
167171

168172
void check$java_net_URLConnection$$setContentHandlerFactory(Class<?> callerClass, ContentHandlerFactory fac);
169173

174+
////////////////////
175+
//
176+
// Network access
177+
//
178+
void check$java_net_ProxySelector$$setDefault(Class<?> callerClass, ProxySelector ps);
179+
180+
void check$java_net_ResponseCache$$setDefault(Class<?> callerClass, ResponseCache rc);
181+
182+
void check$java_net_spi_InetAddressResolverProvider$(Class<?> callerClass);
183+
184+
void check$java_net_spi_URLStreamHandlerProvider$(Class<?> callerClass);
185+
186+
void check$java_net_URL$(Class<?> callerClass, String protocol, String host, int port, String file, URLStreamHandler handler);
187+
188+
void check$java_net_URL$(Class<?> callerClass, URL context, String spec, URLStreamHandler handler);
189+
190+
// The only implementation of SSLSession#getSessionContext(); unfortunately it's an interface, so we need to check the implementation
191+
void check$sun_security_ssl_SSLSessionImpl$getSessionContext(Class<?> callerClass, SSLSession sslSession);
170192
}

libs/entitlement/qa/common/src/main/java/org/elasticsearch/entitlement/qa/common/RestEntitlementsCheckAction.java

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,19 @@
3434
import java.io.IOException;
3535
import java.io.UncheckedIOException;
3636
import java.net.DatagramSocket;
37-
import java.net.DatagramSocketImpl;
38-
import java.net.DatagramSocketImplFactory;
3937
import java.net.HttpURLConnection;
38+
import java.net.MalformedURLException;
39+
import java.net.ProxySelector;
40+
import java.net.ResponseCache;
4041
import java.net.ServerSocket;
4142
import java.net.Socket;
4243
import java.net.URL;
4344
import java.net.URLClassLoader;
4445
import java.net.URLConnection;
46+
import java.net.URLStreamHandler;
47+
import java.net.spi.InetAddressResolver;
48+
import java.net.spi.InetAddressResolverProvider;
49+
import java.net.spi.URLStreamHandlerProvider;
4550
import java.security.NoSuchAlgorithmException;
4651
import java.util.List;
4752
import java.util.Map;
@@ -50,13 +55,17 @@
5055

5156
import javax.net.ssl.HttpsURLConnection;
5257
import javax.net.ssl.SSLContext;
58+
import javax.net.ssl.SSLSession;
59+
import javax.net.ssl.SSLSocket;
60+
import javax.net.ssl.SSLSocketFactory;
5361

5462
import static java.util.Map.entry;
5563
import static org.elasticsearch.entitlement.qa.common.RestEntitlementsCheckAction.CheckAction.alwaysDenied;
5664
import static org.elasticsearch.entitlement.qa.common.RestEntitlementsCheckAction.CheckAction.deniedToPlugins;
5765
import static org.elasticsearch.entitlement.qa.common.RestEntitlementsCheckAction.CheckAction.forPlugins;
5866
import static org.elasticsearch.rest.RestRequest.Method.GET;
5967

68+
@SuppressWarnings("unused")
6069
public class RestEntitlementsCheckAction extends BaseRestHandler {
6170
private static final Logger logger = LogManager.getLogger(RestEntitlementsCheckAction.class);
6271
public static final Thread NO_OP_SHUTDOWN_HOOK = new Thread(() -> {}, "Shutdown hook for testing");
@@ -125,9 +134,87 @@ static CheckAction alwaysDenied(Runnable action) {
125134
entry("socket_setSocketImplFactory", alwaysDenied(RestEntitlementsCheckAction::socket$$setSocketImplFactory)),
126135
entry("url_setURLStreamHandlerFactory", alwaysDenied(RestEntitlementsCheckAction::url$$setURLStreamHandlerFactory)),
127136
entry("urlConnection_setFileNameMap", alwaysDenied(RestEntitlementsCheckAction::urlConnection$$setFileNameMap)),
128-
entry("urlConnection_setContentHandlerFactory", alwaysDenied(RestEntitlementsCheckAction::urlConnection$$setContentHandlerFactory))
137+
entry("urlConnection_setContentHandlerFactory", alwaysDenied(RestEntitlementsCheckAction::urlConnection$$setContentHandlerFactory)),
138+
139+
entry("proxySelector_setDefault", alwaysDenied(RestEntitlementsCheckAction::setDefaultProxySelector)),
140+
entry("responseCache_setDefault", alwaysDenied(RestEntitlementsCheckAction::setDefaultResponseCache)),
141+
entry("createInetAddressResolverProvider", alwaysDenied(RestEntitlementsCheckAction::createInetAddressResolverProvider)),
142+
entry("createURLStreamHandlerProvider", alwaysDenied(RestEntitlementsCheckAction::createURLStreamHandlerProvider)),
143+
entry("createURLWithURLStreamHandler", alwaysDenied(RestEntitlementsCheckAction::createURLWithURLStreamHandler)),
144+
entry("createURLWithURLStreamHandler2", alwaysDenied(RestEntitlementsCheckAction::createURLWithURLStreamHandler2)),
145+
entry("sslSessionImpl_getSessionContext", alwaysDenied(RestEntitlementsCheckAction::sslSessionImplGetSessionContext))
129146
);
130147

148+
private static void createURLStreamHandlerProvider() {
149+
var x = new URLStreamHandlerProvider() {
150+
@Override
151+
public URLStreamHandler createURLStreamHandler(String protocol) {
152+
return null;
153+
}
154+
};
155+
}
156+
157+
private static void sslSessionImplGetSessionContext() {
158+
SSLSocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory();
159+
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
160+
SSLSession session = socket.getSession();
161+
162+
session.getSessionContext();
163+
} catch (IOException e) {
164+
throw new RuntimeException(e);
165+
}
166+
}
167+
168+
@SuppressWarnings("deprecation")
169+
private static void createURLWithURLStreamHandler() {
170+
try {
171+
var x = new URL("http", "host", 1234, "file", new URLStreamHandler() {
172+
@Override
173+
protected URLConnection openConnection(URL u) {
174+
return null;
175+
}
176+
});
177+
} catch (MalformedURLException e) {
178+
throw new RuntimeException(e);
179+
}
180+
}
181+
182+
@SuppressWarnings("deprecation")
183+
private static void createURLWithURLStreamHandler2() {
184+
try {
185+
var x = new URL(null, "spec", new URLStreamHandler() {
186+
@Override
187+
protected URLConnection openConnection(URL u) {
188+
return null;
189+
}
190+
});
191+
} catch (MalformedURLException e) {
192+
throw new RuntimeException(e);
193+
}
194+
}
195+
196+
private static void createInetAddressResolverProvider() {
197+
var x = new InetAddressResolverProvider() {
198+
@Override
199+
public InetAddressResolver get(Configuration configuration) {
200+
return null;
201+
}
202+
203+
@Override
204+
public String name() {
205+
return "TEST";
206+
}
207+
};
208+
}
209+
210+
private static void setDefaultResponseCache() {
211+
ResponseCache.setDefault(null);
212+
}
213+
214+
private static void setDefaultProxySelector() {
215+
ProxySelector.setDefault(null);
216+
}
217+
131218
private static void setDefaultSSLContext() {
132219
try {
133220
SSLContext.setDefault(SSLContext.getDefault());
@@ -270,12 +357,7 @@ private static void setHttpsConnectionProperties() {
270357
@SuppressForbidden(reason = "We're required to prevent calls to this forbidden API")
271358
private static void datagramSocket$$setDatagramSocketImplFactory() {
272359
try {
273-
DatagramSocket.setDatagramSocketImplFactory(new DatagramSocketImplFactory() {
274-
@Override
275-
public DatagramSocketImpl createDatagramSocketImpl() {
276-
throw new IllegalStateException();
277-
}
278-
});
360+
DatagramSocket.setDatagramSocketImplFactory(() -> { throw new IllegalStateException(); });
279361
} catch (IOException e) {
280362
throw new IllegalStateException(e);
281363
}

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@
1818
import java.net.ContentHandlerFactory;
1919
import java.net.DatagramSocketImplFactory;
2020
import java.net.FileNameMap;
21+
import java.net.ProxySelector;
22+
import java.net.ResponseCache;
2123
import java.net.SocketImplFactory;
2224
import java.net.URL;
25+
import java.net.URLStreamHandler;
2326
import java.net.URLStreamHandlerFactory;
2427
import java.util.List;
2528

2629
import javax.net.ssl.HostnameVerifier;
2730
import javax.net.ssl.HttpsURLConnection;
2831
import javax.net.ssl.SSLContext;
32+
import javax.net.ssl.SSLSession;
2933
import javax.net.ssl.SSLSocketFactory;
3034

3135
/**
@@ -310,4 +314,39 @@ public ElasticsearchEntitlementChecker(PolicyManager policyManager) {
310314
public void check$javax_net_ssl_SSLContext$$setDefault(Class<?> callerClass, SSLContext context) {
311315
policyManager.checkChangeJVMGlobalState(callerClass);
312316
}
317+
318+
@Override
319+
public void check$java_net_ProxySelector$$setDefault(Class<?> callerClass, ProxySelector ps) {
320+
policyManager.checkChangeNetworkHandling(callerClass);
321+
}
322+
323+
@Override
324+
public void check$java_net_ResponseCache$$setDefault(Class<?> callerClass, ResponseCache rc) {
325+
policyManager.checkChangeNetworkHandling(callerClass);
326+
}
327+
328+
@Override
329+
public void check$java_net_spi_InetAddressResolverProvider$(Class<?> callerClass) {
330+
policyManager.checkChangeNetworkHandling(callerClass);
331+
}
332+
333+
@Override
334+
public void check$java_net_spi_URLStreamHandlerProvider$(Class<?> callerClass) {
335+
policyManager.checkChangeNetworkHandling(callerClass);
336+
}
337+
338+
@Override
339+
public void check$java_net_URL$(Class<?> callerClass, String protocol, String host, int port, String file, URLStreamHandler handler) {
340+
policyManager.checkChangeNetworkHandling(callerClass);
341+
}
342+
343+
@Override
344+
public void check$java_net_URL$(Class<?> callerClass, URL context, String spec, URLStreamHandler handler) {
345+
policyManager.checkChangeNetworkHandling(callerClass);
346+
}
347+
348+
@Override
349+
public void check$sun_security_ssl_SSLSessionImpl$getSessionContext(Class<?> callerClass, SSLSession sslSession) {
350+
policyManager.checkReadSensitiveNetworkInformation(callerClass);
351+
}
313352
}

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ public void checkChangeJVMGlobalState(Class<?> callerClass) {
171171
});
172172
}
173173

174+
/**
175+
* Check for operations that can modify the way network operations are handled
176+
*/
177+
public void checkChangeNetworkHandling(Class<?> callerClass) {
178+
checkChangeJVMGlobalState(callerClass);
179+
}
180+
181+
/**
182+
* Check for operations that can access sensitive network information, e.g. secrets, tokens or SSL sessions
183+
*/
184+
public void checkReadSensitiveNetworkInformation(Class<?> callerClass) {
185+
neverEntitled(callerClass, "access sensitive network information");
186+
}
187+
174188
private String operationDescription(String methodName) {
175189
// TODO: Use a more human-readable description. Perhaps share code with InstrumentationServiceImpl.parseCheckerMethodName
176190
return methodName.substring(methodName.indexOf('$'));

0 commit comments

Comments
 (0)