From ab690ba23f0a7546a7adbc19c68ed31c81a0fb6c Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Thu, 8 May 2025 16:59:03 -0700 Subject: [PATCH] Check hidden frames in entitlements (#127877) Entitlements do a stack walk to find the calling class. When method refences are used in a lambda, the frame ends up hidden in the stack walk. In the case of using a method reference with AccessController.doPrivileged, the call looks like it is the jdk itself, so the call is trivially allowed. This commit adds hidden frames to the stack walk so that the lambda frame created for the method reference is included. Several internal packages are then necessary to filter out of the stack. --- docs/changelog/127877.yaml | 5 +++++ .../java/org/elasticsearch/entitlement/bridge/Util.java | 7 ++++++- .../runtime/policy/entitlements/FilesEntitlement.java | 4 +++- .../src/main/plugin-metadata/entitlement-policy.yaml | 6 ++++++ 4 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 docs/changelog/127877.yaml diff --git a/docs/changelog/127877.yaml b/docs/changelog/127877.yaml new file mode 100644 index 000000000000..58f2504e41c3 --- /dev/null +++ b/docs/changelog/127877.yaml @@ -0,0 +1,5 @@ +pr: 127877 +summary: Check hidden frames in entitlements +area: Infra/Core +type: bug +issues: [] diff --git a/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/Util.java b/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/Util.java index 9fd34d3b72c2..a6eb17493fa1 100644 --- a/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/Util.java +++ b/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/Util.java @@ -10,8 +10,10 @@ package org.elasticsearch.entitlement.bridge; import java.util.Optional; +import java.util.Set; import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE; +import static java.lang.StackWalker.Option.SHOW_HIDDEN_FRAMES; public class Util { /** @@ -23,6 +25,8 @@ public class Util { public static final Class NO_CLASS = new Object() { }.getClass(); + private static final Set skipInternalPackages = Set.of("java.lang.invoke", "java.lang.reflect", "jdk.internal.reflect"); + /** * Why would we write this instead of using {@link StackWalker#getCallerClass()}? * Because that method throws {@link IllegalCallerException} if called from the "outermost frame", @@ -32,9 +36,10 @@ public class Util { */ @SuppressWarnings("unused") // Called reflectively from InstrumenterImpl public static Class getCallerClass() { - Optional> callerClassIfAny = StackWalker.getInstance(RETAIN_CLASS_REFERENCE) + Optional> callerClassIfAny = StackWalker.getInstance(Set.of(RETAIN_CLASS_REFERENCE, SHOW_HIDDEN_FRAMES)) .walk( frames -> frames.skip(2) // Skip this method and its caller + .filter(frame -> skipInternalPackages.contains(frame.getDeclaringClass().getPackageName()) == false) .findFirst() .map(StackWalker.StackFrame::getDeclaringClass) ); diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java index b15280a9279b..1eab0886bcb5 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java @@ -182,7 +182,9 @@ public record FilesEntitlement(List filesData) implements Entitlement case "config" -> BaseDir.CONFIG; case "data" -> BaseDir.DATA; case "home" -> BaseDir.USER_HOME; - // NOTE: shared_repo is _not_ accessible to policy files, only internally + // it would be nice to limit this to just ES modules, but we don't have a way to plumb that through to here + // however, we still don't document in the error case below that shared_repo is valid + case "shared_repo" -> BaseDir.SHARED_REPO; default -> throw new PolicyValidationException( "invalid relative directory: " + baseDir + ", valid values: [config, data, home]" ); diff --git a/modules/repository-url/src/main/plugin-metadata/entitlement-policy.yaml b/modules/repository-url/src/main/plugin-metadata/entitlement-policy.yaml index 081ac21f8886..2a8ea227e701 100644 --- a/modules/repository-url/src/main/plugin-metadata/entitlement-policy.yaml +++ b/modules/repository-url/src/main/plugin-metadata/entitlement-policy.yaml @@ -1,2 +1,8 @@ +org.elasticsearch.repository.url: + - outbound_network + - files: + - relative_path: . + relative_to: shared_repo + mode: read org.apache.httpcomponents.httpclient: - outbound_network # for URLHttpClient