瀏覽代碼

Remove java.xml from system modules (#133671)

java.xml is part of the jdk, but it's really a utility module that
shouldn't have direct access to network or files. This commit excludes
java.xml from system modules. Note that since it is part of the jdk, it
does need access to read jdk classes, so a new internal entitlement is
also added to allow reading jrt urls.
Ryan Ernst 1 月之前
父節點
當前提交
032208905c

+ 5 - 0
docs/changelog/133671.yaml

@@ -0,0 +1,5 @@
+pr: 133671
+summary: Remove `java.xml` from system modules
+area: Infra/Core
+type: bug
+issues: []

+ 9 - 0
libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java

@@ -13,6 +13,7 @@ import org.elasticsearch.core.CheckedRunnable;
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.entitlement.qa.entitled.EntitledActions;
 import org.elasticsearch.env.Environment;
+import org.xml.sax.helpers.DefaultHandler;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -39,6 +40,7 @@ import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
 
 import javax.imageio.stream.FileImageInputStream;
+import javax.xml.parsers.SAXParserFactory;
 
 import static java.nio.charset.Charset.defaultCharset;
 import static java.nio.file.StandardOpenOption.CREATE;
@@ -610,5 +612,12 @@ class FileCheckActions {
         new FileImageInputStream(file.toFile()).close();
     }
 
+    @EntitlementTest(expectedAccess = ALWAYS_DENIED)
+    static void javaXmlFileRequest() throws Exception {
+        // java.xml is part of the jdk, but not a system module. this checks it can't access files
+        var saxParser = SAXParserFactory.newInstance().newSAXParser();
+        saxParser.parse(readFile().toFile(), new DefaultHandler());
+    }
+
     private FileCheckActions() {}
 }

+ 10 - 0
libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/JvmActions.java

@@ -18,6 +18,9 @@ import java.net.URLClassLoader;
 import java.util.Locale;
 import java.util.TimeZone;
 
+import javax.xml.parsers.SAXParserFactory;
+
+import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_ALLOWED;
 import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_DENIED;
 import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
 
@@ -80,5 +83,12 @@ class JvmActions {
         Thread.setDefaultUncaughtExceptionHandler(Thread.getDefaultUncaughtExceptionHandler());
     }
 
+    @EntitlementTest(expectedAccess = ALWAYS_ALLOWED)
+    static void useJavaXmlParser() {
+        // java.xml is part of the jdk, but not a system module. this checks it's actually usable
+        // as it needs to read classes from the jdk which is not generally allowed
+        SAXParserFactory.newInstance();
+    }
+
     private JvmActions() {}
 }

+ 9 - 0
libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/NetworkAccessCheckActions.java

@@ -10,6 +10,7 @@
 package org.elasticsearch.entitlement.qa.test;
 
 import org.elasticsearch.core.SuppressForbidden;
+import org.xml.sax.helpers.DefaultHandler;
 
 import java.io.IOException;
 import java.net.DatagramPacket;
@@ -46,6 +47,7 @@ import java.util.concurrent.ExecutionException;
 
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
+import javax.xml.parsers.SAXParserFactory;
 
 import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_DENIED;
 import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
@@ -434,5 +436,12 @@ class NetworkAccessCheckActions {
         }
     }
 
+    @EntitlementTest(expectedAccess = ALWAYS_DENIED)
+    static void javaXmlNetworkRequest() throws Exception {
+        // java.xml is part of the jdk, but not a system module. this checks it can't access the network
+        var saxParser = SAXParserFactory.newInstance().newSAXParser();
+        saxParser.parse("http://127.0.0.1/foo.json", new DefaultHandler());
+    }
+
     private NetworkAccessCheckActions() {}
 }

+ 16 - 0
libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java

@@ -21,6 +21,7 @@ import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkE
 import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.ManageThreadsEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement;
+import org.elasticsearch.entitlement.runtime.policy.entitlements.ReadJdkImageEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.ReadStoreAttributesEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.SetHttpsConnectionPropertiesEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.WriteSystemPropertiesEntitlement;
@@ -114,6 +115,21 @@ class HardcodedEntitlements {
                 )
             ),
             new Scope("java.desktop", List.of(new LoadNativeLibrariesEntitlement())),
+            new Scope(
+                "java.xml",
+                List.of(
+                    new ReadJdkImageEntitlement(),
+                    // java.xml does some reflective stuff that reads calling jars, so allow reading the codebases
+                    // of any code in the system so that they can all use java.xml
+                    new FilesEntitlement(
+                        List.of(
+                            FilesEntitlement.FileData.ofBaseDirPath(LIB, READ),
+                            FilesEntitlement.FileData.ofBaseDirPath(MODULES, READ),
+                            FilesEntitlement.FileData.ofBaseDirPath(PLUGINS, READ)
+                        )
+                    )
+                )
+            ),
             new Scope("org.apache.httpcomponents.httpclient", List.of(new OutboundNetworkEntitlement())),
             new Scope(
                 "org.apache.lucene.core",

+ 7 - 0
libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyCheckerImpl.java

@@ -21,6 +21,7 @@ import org.elasticsearch.entitlement.runtime.policy.entitlements.InboundNetworkE
 import org.elasticsearch.entitlement.runtime.policy.entitlements.LoadNativeLibrariesEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.ManageThreadsEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.OutboundNetworkEntitlement;
+import org.elasticsearch.entitlement.runtime.policy.entitlements.ReadJdkImageEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.ReadStoreAttributesEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.SetHttpsConnectionPropertiesEntitlement;
 import org.elasticsearch.entitlement.runtime.policy.entitlements.WriteSystemPropertiesEntitlement;
@@ -490,6 +491,8 @@ public class PolicyCheckerImpl implements PolicyChecker {
             if (jarFileUrl == null || handleNetworkOrFileUrlCheck(callerClass, jarFileUrl) == false) {
                 checkUnsupportedURLProtocolConnection(callerClass, "jar with unsupported inner protocol");
             }
+        } else if (isJrtUrl(url)) {
+            checkEntitlementPresent(callerClass, ReadJdkImageEntitlement.class);
         } else {
             checkUnsupportedURLProtocolConnection(callerClass, url.getProtocol());
         }
@@ -560,6 +563,10 @@ public class PolicyCheckerImpl implements PolicyChecker {
         return "jar".equals(url.getProtocol());
     }
 
+    private static boolean isJrtUrl(java.net.URL url) {
+        return "jrt".equals(url.getProtocol());
+    }
+
     // We have to use class names for sun.net.www classes as java.base does not export them
     private static final List<String> ADDITIONAL_NETWORK_URL_CONNECT_CLASS_NAMES = List.of(
         "sun.net.www.protocol.ftp.FtpURLConnection",

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

@@ -54,7 +54,7 @@ public class PolicyManager {
      */
     static final Logger generalLogger = LogManager.getLogger(PolicyManager.class);
 
-    static final Set<String> MODULES_EXCLUDED_FROM_SYSTEM_MODULES = Set.of("java.desktop");
+    static final Set<String> MODULES_EXCLUDED_FROM_SYSTEM_MODULES = Set.of("java.desktop", "java.xml");
 
     /**
      * Identifies a particular entitlement {@link Scope} within a {@link Policy}.

+ 19 - 0
libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/ReadJdkImageEntitlement.java

@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the "Elastic License
+ * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
+ * Public License v 1"; you may not use this file except in compliance with, at
+ * your election, the "Elastic License 2.0", the "GNU Affero General Public
+ * License v3.0 only", or the "Server Side Public License, v 1".
+ */
+
+package org.elasticsearch.entitlement.runtime.policy.entitlements;
+
+/**
+ * Internal entitlement to read code from the jdk.
+ *
+ * Concretely this means the code can open jrt urls. Since the java
+ * runtime images (jrt) are read only, this implicitly only allows
+ * reading those urls.
+ */
+public class ReadJdkImageEntitlement implements Entitlement {}