From a33403fb1dcd781845a851c980d563aa5ddf9415 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 0000000000000..58f2504e41c33 --- /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 9fd34d3b72c2c..a6eb17493fa1f 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 b15280a9279b6..1eab0886bcb5b 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 @@ private static BaseDir parseBaseDir(String baseDir) { 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 081ac21f88864..2a8ea227e701b 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