Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.16.2] Tolerate unprivileged log4j getClassLoaders calls #81903

Merged
merged 1 commit into from
Dec 18, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -58,6 +60,26 @@ final class ESPolicy extends Policy {
this.plugins = plugins;
}

private static final Predicate<StackTraceElement> JDK_BOOT = f -> f.getClassName().startsWith("java.lang.")
|| f.getClassName().startsWith("java.security.");
private static final Predicate<StackTraceElement> ES_BOOTSTRAP = f -> f.getClassName().startsWith("org.elasticsearch.bootstrap");
private static final Predicate<StackTraceElement> 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<StackTraceElement> 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) {
Expand Down Expand Up @@ -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);
}
Expand Down