diff --git a/server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java b/server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java index 2f824aee56af..e23d183884bb 100644 --- a/server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java +++ b/server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java @@ -20,8 +20,10 @@ import java.security.Permissions; import java.security.Policy; import java.security.ProtectionDomain; +import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.Optional; import java.util.function.Predicate; /** custom policy for union of static and dynamic permissions */ @@ -58,6 +60,26 @@ final class ESPolicy extends Policy { this.plugins = plugins; } + private static final Predicate JDK_BOOT = f -> f.getClassName().startsWith("java.lang.") + || f.getClassName().startsWith("java.security."); + private static final Predicate ES_BOOTSTRAP = f -> f.getClassName().startsWith("org.elasticsearch.bootstrap"); + private static final Predicate IS_LOG4J = f -> "org.apache.logging.log4j.util.LoaderUtil".equals(f.getClassName()) + && "getClassLoaders".equals(f.getMethodName()); + + /** + * Returns true if the top of the call stack has: + * 1) Only frames belonging from the JDK's boot loader or org.elasticsearch.bootstrap, followed directly by + * 2) org.apache.logging.log4j.util.LoaderUtil.getClassLoaders + */ + private static boolean isLoaderUtilGetClassLoaders() { + Optional frame = Arrays.stream(Thread.currentThread().getStackTrace()) + .filter(JDK_BOOT.or(ES_BOOTSTRAP).negate()) + .limit(1) + .findFirst() + .filter(IS_LOG4J); + return frame.isPresent(); + } + @Override @SuppressForbidden(reason = "fast equals check is desired") public boolean implies(ProtectionDomain domain, Permission permission) { @@ -101,6 +123,10 @@ public boolean implies(ProtectionDomain domain, Permission permission) { return true; } + if (permission instanceof RuntimePermission && "getClassLoader".equals(permission.getName()) && isLoaderUtilGetClassLoaders()) { + return true; + } + // otherwise defer to template + dynamic file permissions return template.implies(domain, permission) || dynamic.implies(permission) || system.implies(domain, permission); }