Skip to content

Commit 8ef81ed

Browse files
authored
[7.16] Tolerate unprivileged log4j getClassLoaders calls (#81903)
1 parent 63d6e6a commit 8ef81ed

File tree

1 file changed

+26
-0
lines changed

1 file changed

+26
-0
lines changed

server/src/main/java/org/elasticsearch/bootstrap/ESPolicy.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import java.security.Permissions;
2121
import java.security.Policy;
2222
import java.security.ProtectionDomain;
23+
import java.util.Arrays;
2324
import java.util.Collections;
2425
import java.util.Map;
26+
import java.util.Optional;
2527
import java.util.function.Predicate;
2628

2729
/** custom policy for union of static and dynamic permissions */
@@ -58,6 +60,26 @@ final class ESPolicy extends Policy {
5860
this.plugins = plugins;
5961
}
6062

63+
private static final Predicate<StackTraceElement> JDK_BOOT = f -> f.getClassName().startsWith("java.lang.")
64+
|| f.getClassName().startsWith("java.security.");
65+
private static final Predicate<StackTraceElement> ES_BOOTSTRAP = f -> f.getClassName().startsWith("org.elasticsearch.bootstrap");
66+
private static final Predicate<StackTraceElement> IS_LOG4J = f -> "org.apache.logging.log4j.util.LoaderUtil".equals(f.getClassName())
67+
&& "getClassLoaders".equals(f.getMethodName());
68+
69+
/**
70+
* Returns true if the top of the call stack has:
71+
* 1) Only frames belonging from the JDK's boot loader or org.elasticsearch.bootstrap, followed directly by
72+
* 2) org.apache.logging.log4j.util.LoaderUtil.getClassLoaders
73+
*/
74+
private static boolean isLoaderUtilGetClassLoaders() {
75+
Optional<StackTraceElement> frame = Arrays.stream(Thread.currentThread().getStackTrace())
76+
.filter(JDK_BOOT.or(ES_BOOTSTRAP).negate())
77+
.limit(1)
78+
.findFirst()
79+
.filter(IS_LOG4J);
80+
return frame.isPresent();
81+
}
82+
6183
@Override
6284
@SuppressForbidden(reason = "fast equals check is desired")
6385
public boolean implies(ProtectionDomain domain, Permission permission) {
@@ -101,6 +123,10 @@ public boolean implies(ProtectionDomain domain, Permission permission) {
101123
return true;
102124
}
103125

126+
if (permission instanceof RuntimePermission && "getClassLoader".equals(permission.getName()) && isLoaderUtilGetClassLoaders()) {
127+
return true;
128+
}
129+
104130
// otherwise defer to template + dynamic file permissions
105131
return template.implies(domain, permission) || dynamic.implies(permission) || system.implies(domain, permission);
106132
}

0 commit comments

Comments
 (0)