Browse Source

Improve security manager support (#11466)

Lauri Tulmin 9 months ago
parent
commit
e7d0278fc8

+ 16 - 6
instrumentation-api/src/main/java/io/opentelemetry/instrumentation/api/internal/SupportabilityMetrics.java

@@ -6,6 +6,7 @@
 package io.opentelemetry.instrumentation.api.internal;
 
 import io.opentelemetry.api.trace.SpanKind;
+import java.security.PrivilegedAction;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.Executors;
@@ -88,12 +89,14 @@ public final class SupportabilityMetrics {
       ScheduledExecutorService executor =
           Executors.newScheduledThreadPool(
               1,
-              runnable -> {
-                Thread result = new Thread(runnable, "supportability_metrics_reporter");
-                result.setDaemon(true);
-                result.setContextClassLoader(null);
-                return result;
-              });
+              runnable ->
+                  doPrivileged(
+                      () -> {
+                        Thread result = new Thread(runnable, "supportability_metrics_reporter");
+                        result.setDaemon(true);
+                        result.setContextClassLoader(null);
+                        return result;
+                      }));
       executor.scheduleAtFixedRate(this::report, 5, 5, TimeUnit.SECONDS);
       // the condition below will always be false, but by referencing the executor it ensures the
       // executor can't become unreachable in the middle of the scheduleAtFixedRate() method
@@ -107,6 +110,13 @@ public final class SupportabilityMetrics {
     return this;
   }
 
+  private static <T> T doPrivileged(PrivilegedAction<T> action) {
+    if (System.getSecurityManager() == null) {
+      return action.run();
+    }
+    return java.security.AccessController.doPrivileged(action);
+  }
+
   /**
    * This class is internal and is hence not for public use. Its APIs are unstable and can change at
    * any time.

+ 5 - 1
javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/AgentInitializer.java

@@ -58,7 +58,11 @@ public final class AgentInitializer {
   }
 
   private static void execute(PrivilegedExceptionAction<Void> action) throws Exception {
-    if (isSecurityManagerSupportEnabled && System.getSecurityManager() != null) {
+    // When security manager support is enabled we use doPrivileged even if security manager is not
+    // present because security manager could be installed later. ByteBuddy initialization captures
+    // the access control context used during transformation. If we don't use doPrivileged here then
+    // that context will not have the privileges if security manager is installed later.
+    if (isSecurityManagerSupportEnabled) {
       doPrivilegedExceptionAction(action);
     } else {
       action.run();

+ 10 - 0
javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/field/RuntimeFieldBasedImplementationSupplier.java

@@ -11,6 +11,7 @@ import io.opentelemetry.instrumentation.api.internal.RuntimeVirtualFieldSupplier
 import io.opentelemetry.instrumentation.api.util.VirtualField;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.security.PrivilegedAction;
 
 final class RuntimeFieldBasedImplementationSupplier
     implements RuntimeVirtualFieldSupplier.VirtualFieldSupplier {
@@ -18,6 +19,15 @@ final class RuntimeFieldBasedImplementationSupplier
   @Override
   public <U extends T, V extends F, T, F> VirtualField<U, V> find(
       Class<T> type, Class<F> fieldType) {
+    if (System.getSecurityManager() == null) {
+      return findInternal(type, fieldType);
+    }
+    return java.security.AccessController.doPrivileged(
+        (PrivilegedAction<VirtualField<U, V>>) () -> findInternal(type, fieldType));
+  }
+
+  private static <U extends T, V extends F, T, F> VirtualField<U, V> findInternal(
+      Class<T> type, Class<F> fieldType) {
     try {
       String virtualFieldImplClassName =
           getVirtualFieldImplementationClassName(type.getTypeName(), fieldType.getTypeName());