Skip to content
5 changes: 5 additions & 0 deletions docs/changelog/133671.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 133671
summary: Remove `java.xml` from system modules
area: Infra/Core
type: bug
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
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;
Expand All @@ -39,6 +40,7 @@
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;
Expand Down Expand Up @@ -610,5 +612,12 @@ static void javaDesktopFileAccess() throws Exception {
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() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
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;

Expand Down Expand Up @@ -80,5 +83,12 @@ static void createLogManager() {
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() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -46,6 +47,7 @@

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;
Expand Down Expand Up @@ -434,5 +436,12 @@ static void receiveDatagramSocket() throws IOException {
}
}

@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() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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;
Expand Down Expand Up @@ -114,6 +115,21 @@ private static List<Scope> createServerEntitlements(Path pidFile) {
)
),
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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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;
Expand Down Expand Up @@ -490,6 +491,8 @@ public void checkEntitlementForUrl(Class<?> callerClass, URL url) {
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());
}
Expand Down Expand Up @@ -560,6 +563,10 @@ private static boolean isJarUrl(java.net.URL url) {
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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}.
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {}