8139884: Use privileged blocks when working with class loaders
authorattila
Mon, 19 Oct 2015 22:36:03 +0200
changeset 33336 47279b2180b4
parent 33335 a46c85103868
child 33337 af3fea63e008
8139884: Use privileged blocks when working with class loaders Reviewed-by: hannesw, mhaupt, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ClassMap.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassString.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedMethod.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ClassMap.java	Mon Oct 19 18:24:47 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/ClassMap.java	Mon Oct 19 22:36:03 2015 +0200
@@ -150,15 +150,15 @@
         final T newV = computeValue(clazz);
         assert newV != null;
 
-        final ClassLoader clazzLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+        final Boolean canReferenceDirectly = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
             @Override
-            public ClassLoader run() {
-                return clazz.getClassLoader();
+            public Boolean run() {
+                return Guards.canReferenceDirectly(classLoader, clazz.getClassLoader());
             }
         }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT);
 
         // If allowed to strongly reference, put it in the fast map
-        if(Guards.canReferenceDirectly(classLoader, clazzLoader)) {
+        if(canReferenceDirectly) {
             final T oldV = map.putIfAbsent(clazz, newV);
             return oldV != null ? oldV : newV;
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassString.java	Mon Oct 19 18:24:47 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/ClassString.java	Mon Oct 19 22:36:03 2015 +0200
@@ -85,6 +85,9 @@
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodType;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
 import java.util.LinkedList;
 import java.util.List;
 import jdk.internal.dynalink.linker.LinkerServices;
@@ -97,6 +100,8 @@
  * JLS.
  */
 final class ClassString {
+    private static final Permission GET_CLASS_LOADER_PERMISSION = new RuntimePermission("getClassLoader");
+
     /**
      * An anonymous inner class used solely to represent the "type" of null values for method applicability checking.
      */
@@ -143,12 +148,17 @@
     }
 
     boolean isVisibleFrom(final ClassLoader classLoader) {
-        for(int i = 0; i < classes.length; ++i) {
-            if(!Guards.canReferenceDirectly(classLoader, classes[i].getClassLoader())) {
-                return false;
+        return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                for(final Class<?> clazz: classes) {
+                    if(!Guards.canReferenceDirectly(classLoader, clazz.getClassLoader())) {
+                        return false;
+                    }
+                }
+                return true;
             }
-        }
-        return true;
+        }, null, GET_CLASS_LOADER_PERMISSION);
     }
 
     List<MethodHandle> getMaximallySpecifics(final List<MethodHandle> methods, final LinkerServices linkerServices, final boolean varArg) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Mon Oct 19 18:24:47 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Mon Oct 19 22:36:03 2015 +0200
@@ -85,6 +85,11 @@
 
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodType;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
 import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -218,10 +223,27 @@
                 for(final SingleDynamicMethod method: invokables) {
                     methodHandles.add(method.getTarget(callSiteDescriptor));
                 }
-                return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker();
+                return new OverloadedMethod(methodHandles, this, getCallSiteClassLoader(callSiteDescriptor), callSiteType, linkerServices).getInvoker();
             }
         }
+    }
 
+    private static final AccessControlContext GET_CALL_SITE_CLASS_LOADER_CONTEXT;
+    static {
+        final Permissions perms = new Permissions();
+        perms.add(new RuntimePermission("getClassLoader"));
+        perms.add(CallSiteDescriptor.GET_LOOKUP_PERMISSION);
+        GET_CALL_SITE_CLASS_LOADER_CONTEXT = new AccessControlContext(
+                new ProtectionDomain[] { new ProtectionDomain(null, perms) });
+    }
+
+    private static ClassLoader getCallSiteClassLoader(final CallSiteDescriptor callSiteDescriptor) {
+        return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+            @Override
+            public ClassLoader run() {
+                return callSiteDescriptor.getLookup().lookupClass().getClassLoader();
+            }
+        }, GET_CALL_SITE_CLASS_LOADER_CONTEXT);
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedMethod.java	Mon Oct 19 18:24:47 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedMethod.java	Mon Oct 19 22:36:03 2015 +0200
@@ -104,15 +104,20 @@
 class OverloadedMethod {
     private final Map<ClassString, MethodHandle> argTypesToMethods = new ConcurrentHashMap<>();
     private final OverloadedDynamicMethod parent;
+    private final ClassLoader callSiteClassLoader;
     private final MethodType callSiteType;
     private final MethodHandle invoker;
     private final LinkerServices linkerServices;
     private final ArrayList<MethodHandle> fixArgMethods;
     private final ArrayList<MethodHandle> varArgMethods;
 
-    OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
+    OverloadedMethod(final List<MethodHandle> methodHandles,
+            final OverloadedDynamicMethod parent,
+            final ClassLoader callSiteClassLoader,
+            final MethodType callSiteType,
             final LinkerServices linkerServices) {
         this.parent = parent;
+        this.callSiteClassLoader = callSiteClassLoader;
         final Class<?> commonRetType = getCommonReturnType(methodHandles);
         this.callSiteType = callSiteType.changeReturnType(commonRetType);
         this.linkerServices = linkerServices;
@@ -179,7 +184,7 @@
             }
             // Avoid keeping references to unrelated classes; this ruins the performance a bit, but avoids class loader
             // memory leaks.
-            if(classString.isVisibleFrom(parent.getClassLoader())) {
+            if(classString.isVisibleFrom(callSiteClassLoader)) {
                 argTypesToMethods.put(classString, method);
             }
         }