You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2022/09/02 23:10:48 UTC

[logging-log4j2] 01/02: LOG4J2-3579 Calls ServiceLoader with caller's security context

This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 880acdfdb0b3c13c73c9ab3375924e238814f948
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Sun Aug 21 22:00:48 2022 +0200

    LOG4J2-3579 Calls ServiceLoader with caller's security context
    
    When running with a security manager, `ServiceLoaderUtil` will call
    `ServiceLoader` with the privileges of the caller.
---
 .../logging/log4j/util/ServiceLoaderUtil.java      | 32 ++++++++++++++++++----
 .../logging/log4j/util/ServiceLoaderUtil.java      | 32 ++++++++++++++++++----
 2 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/log4j-api-java9/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java b/log4j-api-java9/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
index 9450e539a8..10b8cd547d 100644
--- a/log4j-api-java9/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
+++ b/log4j-api-java9/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
@@ -17,10 +17,13 @@
 
 package org.apache.logging.log4j.util;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaMetafactory;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
-import java.util.Arrays;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.ServiceConfigurationError;
@@ -32,9 +35,6 @@ import org.apache.logging.log4j.status.StatusLogger;
 
 public final class ServiceLoaderUtil {
 
-    private static final MethodType LOAD_CLASS_CLASSLOADER = MethodType.methodType(ServiceLoader.class, Class.class,
-            ClassLoader.class);
-
     private ServiceLoaderUtil() {
     }
 
@@ -87,8 +87,28 @@ public final class ServiceLoaderUtil {
     static <T> Stream<T> loadClassloaderServices(final Class<T> serviceType, final Lookup lookup,
             final ClassLoader classLoader, final boolean verbose) {
         try {
-            final MethodHandle handle = lookup.findStatic(ServiceLoader.class, "load", LOAD_CLASS_CLASSLOADER);
-            final ServiceLoader<T> serviceLoader = (ServiceLoader<T>) handle.invokeExact(serviceType, classLoader);
+            // Creates a lambda in the caller's domain that calls `ServiceLoader`
+            final MethodHandle loadHandle = lookup.findStatic(ServiceLoader.class, "load",
+                    MethodType.methodType(ServiceLoader.class, Class.class, ClassLoader.class));
+            final CallSite callSite = LambdaMetafactory.metafactory(lookup,
+                    "run",
+                    MethodType.methodType(PrivilegedAction.class, Class.class, ClassLoader.class),
+                    MethodType.methodType(Object.class),
+                    loadHandle,
+                    MethodType.methodType(ServiceLoader.class));
+            final PrivilegedAction<ServiceLoader<T>> action = (PrivilegedAction<ServiceLoader<T>>) callSite
+                    .getTarget()//
+                    .bindTo(serviceType)
+                    .bindTo(classLoader)
+                    .invoke();
+            final ServiceLoader<T> serviceLoader;
+            if (System.getSecurityManager() == null) {
+                serviceLoader = action.run();
+            } else {
+                final MethodHandle privilegedHandle = lookup.findStatic(AccessController.class, "doPrivileged",
+                        MethodType.methodType(Object.class, PrivilegedAction.class));
+                serviceLoader = (ServiceLoader<T>) privilegedHandle.invoke(action);
+            }
             return serviceLoader.stream().map(provider -> {
                 try {
                     return provider.get();
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
index ab2ddd3934..0230bf403b 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
@@ -17,9 +17,13 @@
 
 package org.apache.logging.log4j.util;
 
+import java.lang.invoke.CallSite;
+import java.lang.invoke.LambdaMetafactory;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -39,9 +43,6 @@ import org.apache.logging.log4j.status.StatusLogger;
  */
 public final class ServiceLoaderUtil {
 
-    private static final MethodType LOAD_CLASS_CLASSLOADER = MethodType.methodType(ServiceLoader.class, Class.class,
-            ClassLoader.class);
-
     private ServiceLoaderUtil() {
     }
 
@@ -102,8 +103,28 @@ public final class ServiceLoaderUtil {
     static <T> Iterable<T> callServiceLoader(Lookup lookup, Class<T> serviceType, ClassLoader classLoader,
             boolean verbose) {
         try {
-            final MethodHandle handle = lookup.findStatic(ServiceLoader.class, "load", LOAD_CLASS_CLASSLOADER);
-            final ServiceLoader<T> serviceLoader = (ServiceLoader<T>) handle.invokeExact(serviceType, classLoader);
+            // Creates a lambda in the caller's domain that calls `ServiceLoader`
+            final MethodHandle loadHandle = lookup.findStatic(ServiceLoader.class, "load",
+                    MethodType.methodType(ServiceLoader.class, Class.class, ClassLoader.class));
+            final CallSite callSite = LambdaMetafactory.metafactory(lookup,
+                    "run",
+                    MethodType.methodType(PrivilegedAction.class, Class.class, ClassLoader.class),
+                    MethodType.methodType(Object.class),
+                    loadHandle,
+                    MethodType.methodType(ServiceLoader.class));
+            final PrivilegedAction<ServiceLoader<T>> action = (PrivilegedAction<ServiceLoader<T>>) callSite
+                    .getTarget()//
+                    .bindTo(serviceType)
+                    .bindTo(classLoader)
+                    .invoke();
+            final ServiceLoader<T> serviceLoader;
+            if (System.getSecurityManager() == null) {
+                serviceLoader = action.run();
+            } else {
+                final MethodHandle privilegedHandle = lookup.findStatic(AccessController.class, "doPrivileged",
+                        MethodType.methodType(Object.class, PrivilegedAction.class));
+                serviceLoader = (ServiceLoader<T>) privilegedHandle.invoke(action);
+            }
             return serviceLoader;
         } catch (Throwable e) {
             if (verbose) {
@@ -111,7 +132,6 @@ public final class ServiceLoaderUtil {
             }
         }
         return Collections.emptyList();
-
     }
 
     private static class ServiceLoaderSpliterator<S> implements Spliterator<S> {