8139435: Make sure CallSiteDescriptor.getLookup is subject to a security check
authorattila
Mon, 19 Oct 2015 08:30:03 +0200
changeset 33331 273e6a10de22
parent 33330 35531ae624ef
child 33332 f180be6368d8
8139435: Make sure CallSiteDescriptor.getLookup is subject to a security check Reviewed-by: hannesw, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/LinkerServicesImpl.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.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/SimpleDynamicMethod.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/SimpleCallSiteDescriptor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java	Mon Oct 19 08:30:03 2015 +0200
@@ -101,6 +101,11 @@
  */
 public interface CallSiteDescriptor {
     /**
+     * A permission to invoke the {@link #getLookup()} method. It is named {@code "dynalink.getLookup"}.
+     */
+    public static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission("dynalink.getLookup");
+
+    /**
      * The index of the name token that will carry the operation scheme prefix (usually, "dyn").
      */
     public static final int SCHEME = 0;
@@ -160,7 +165,8 @@
      * Returns the lookup passed to the bootstrap method.
      * @return the lookup passed to the bootstrap method.
      * @throws SecurityException if the lookup isn't the {@link MethodHandles#publicLookup()} and a security
-     * manager is present, and a check for {@code RuntimePermission("dynalink.getLookup")} fails.
+     * manager is present, and a check for {@code RuntimePermission("dynalink.getLookup")} (available as
+     * {@link #GET_LOOKUP_PERMISSION}) fails.
      */
     public Lookup getLookup();
 
@@ -194,6 +200,25 @@
     }
 
     /**
+     * Checks if the current access context is granted the {@code RuntimePermission("dynalink.getLookup")}
+     * permission, if the system contains a security manager, and the passed lookup is not the
+     * {@link MethodHandles#publicLookup()}.
+     * @param lookup the lookup being checked for access
+     * @return the passed in lookup if there's either no security manager in the system, or the passed lookup
+     * is the public lookup, or the current access context is granted the relevant permission.
+     * @throws SecurityException if the system contains a security manager, and the passed lookup is not the
+     * {@link MethodHandles#publicLookup()}, and the current access context is not granted the relevant
+     * permission.
+     */
+    public static Lookup checkLookup(final Lookup lookup) {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null && lookup != MethodHandles.publicLookup()) {
+            sm.checkPermission(GET_LOOKUP_PERMISSION);
+        }
+        return lookup;
+    }
+
+    /**
      * Tokenizes the composite name along colons, as well as {@link NameCodec#decode(String) demangles} and interns
      * the tokens. The first two tokens are not demangled as they are supposed to be the naming scheme and the name of
      * the operation which can be expected to consist of just alphabetical characters.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java	Mon Oct 19 08:30:03 2015 +0200
@@ -149,6 +149,12 @@
  * </ul>
  */
 public final class DynamicLinker {
+    /**
+     * A permission to invoke the {@link #getCurrentLinkRequest()} method. It is named
+     * {@code "dynalink.getCurrentLinkRequest"}.
+     */
+    public static final RuntimePermission GET_CURRENT_LINK_REQUEST_PERMISSION = new RuntimePermission("dynalink.getCurrentLinkRequest");
+
     private static final String CLASS_NAME = DynamicLinker.class.getName();
     private static final String RELINK_METHOD_NAME = "relink";
 
@@ -321,8 +327,8 @@
     /**
      * Returns the currently processed link request, or null if the method is invoked outside of the linking process.
      * @return the currently processed link request, or null.
-     * @throws SecurityException if the calling code doesn't have the {@code "dynalink.getCurrentLinkRequest"} runtime
-     * permission.
+     * @throws SecurityException if the calling code doesn't have the {@code "dynalink.getCurrentLinkRequest"}
+     * runtime permission (available as {@link #GET_CURRENT_LINK_REQUEST_PERMISSION}).
      */
     public static LinkRequest getCurrentLinkRequest() {
         return LinkerServicesImpl.getCurrentLinkRequest();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/LinkerServicesImpl.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/LinkerServicesImpl.java	Mon Oct 19 08:30:03 2015 +0200
@@ -96,7 +96,6 @@
  * Default implementation of the {@link LinkerServices} interface.
  */
 final class LinkerServicesImpl implements LinkerServices {
-    private static final RuntimePermission GET_CURRENT_LINK_REQUEST = new RuntimePermission("dynalink.getCurrentLinkRequest");
     private static final ThreadLocal<LinkRequest> threadLinkRequest = new ThreadLocal<>();
 
     private final TypeConverterFactory typeConverterFactory;
@@ -159,7 +158,7 @@
         if (currentRequest != null) {
             final SecurityManager sm = System.getSecurityManager();
             if(sm != null) {
-                sm.checkPermission(GET_CURRENT_LINK_REQUEST);
+                sm.checkPermission(DynamicLinker.GET_CURRENT_LINK_REQUEST_PERMISSION);
             }
         }
         return currentRequest;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java	Mon Oct 19 08:30:03 2015 +0200
@@ -568,7 +568,7 @@
     private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
             MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
     private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
-            "getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class, LinkerServices.class));
+            "getTarget", MethodType.methodType(MethodHandle.class, CallSiteDescriptor.class, LinkerServices.class));
     private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
 
     private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
@@ -591,7 +591,7 @@
                 final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
                         AnnotatedDynamicMethod.class));
                 final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
-                        GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup(), linkerServices);
+                        GET_ANNOTATED_METHOD, 1, callSiteDescriptor, linkerServices);
                 final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
                         callSiteBoundMethodGetter);
                 // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
@@ -871,8 +871,8 @@
         }
 
         @SuppressWarnings("unused")
-        MethodHandle getTarget(final MethodHandles.Lookup lookup, final LinkerServices linkerServices) {
-            final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(lookup));
+        MethodHandle getTarget(final CallSiteDescriptor desc, final LinkerServices linkerServices) {
+            final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(desc));
             assert inv != null;
             return inv;
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Mon Oct 19 08:30:03 2015 +0200
@@ -91,12 +91,15 @@
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.support.Lookup;
 
 /**
  * A dynamic method bound to exactly one Java method or constructor that is caller sensitive. Since the target method is
  * caller sensitive, it doesn't cache a method handle but rather uses the passed lookup object in
- * {@link #getTarget(java.lang.invoke.MethodHandles.Lookup)} to unreflect a method handle from the reflective member on
+ * {@link #getTarget(CallSiteDescriptor)} to unreflect a method handle from the reflective member on
  * every request.
  */
 class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
@@ -143,7 +146,11 @@
     }
 
     @Override
-    MethodHandle getTarget(final MethodHandles.Lookup lookup) {
+    MethodHandle getTarget(final CallSiteDescriptor desc) {
+        final MethodHandles.Lookup lookup = AccessController.doPrivileged(
+                (PrivilegedAction<MethodHandles.Lookup>)()->desc.getLookup(), null,
+                CallSiteDescriptor.GET_LOOKUP_PERMISSION);
+
         if(target instanceof Method) {
             final MethodHandle mh = Lookup.unreflect(lookup, (Method)target);
             if(Modifier.isStatic(((Member)target).getModifiers())) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Mon Oct 19 08:30:03 2015 +0200
@@ -84,7 +84,6 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.text.Collator;
 import java.util.ArrayList;
@@ -216,9 +215,8 @@
                 // methods here to their handles, as the OverloadedMethod instance is specific to a call site, so it
                 // has an already determined Lookup.
                 final List<MethodHandle> methodHandles = new ArrayList<>(invokables.size());
-                final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup();
                 for(final SingleDynamicMethod method: invokables) {
-                    methodHandles.add(method.getTarget(lookup));
+                    methodHandles.add(method.getTarget(callSiteDescriptor));
                 }
                 return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker();
             }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Mon Oct 19 08:30:03 2015 +0200
@@ -84,13 +84,13 @@
 package jdk.internal.dynalink.beans;
 
 import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
+import jdk.internal.dynalink.CallSiteDescriptor;
 
 /**
  * A dynamic method bound to exactly one Java method or constructor that is not caller sensitive. Since its target is
  * not caller sensitive, this class pre-caches its method handle and always returns it from the call to
- * {@link #getTarget(Lookup)}. Can be used in general to represents dynamic methods bound to a single method handle,
+ * {@link #getTarget(CallSiteDescriptor)}. Can be used in general to represents dynamic methods bound to a single method handle,
  * even if that handle is not mapped to a Java method, i.e. as a wrapper around field getters/setters, array element
  * getters/setters, etc.
  */
@@ -140,7 +140,7 @@
     }
 
     @Override
-    MethodHandle getTarget(final Lookup lookup) {
+    MethodHandle getTarget(final CallSiteDescriptor desc) {
         return target;
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java	Mon Oct 19 08:30:03 2015 +0200
@@ -119,15 +119,17 @@
     abstract MethodType getMethodType();
 
     /**
-     * Given a specified lookup, returns a method handle to this method's target.
-     * @param lookup the lookup to use.
+     * Given a specified call site descriptor, returns a method handle to this method's target. The target
+     * should only depend on the descriptor's lookup, and it should only retrieve it (as a privileged
+     * operation) when it is absolutely needed.
+     * @param desc the call site descriptor to use.
      * @return the handle to this method's target method.
      */
-    abstract MethodHandle getTarget(MethodHandles.Lookup lookup);
+    abstract MethodHandle getTarget(CallSiteDescriptor desc);
 
     @Override
     MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
-        return getInvocation(getTarget(callSiteDescriptor.getLookup()), callSiteDescriptor.getMethodType(),
+        return getInvocation(getTarget(callSiteDescriptor), callSiteDescriptor.getMethodType(),
                 linkerServices);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java	Mon Oct 19 08:30:03 2015 +0200
@@ -89,30 +89,32 @@
 import jdk.internal.dynalink.CallSiteDescriptor;
 
 /**
- * A base class for call site descriptor implementations. Provides reconstruction of the name from the tokens, as well
- * as a generally useful {@code equals} and {@code hashCode} methods.
+ * A base class for call site descriptor implementations. Provides reconstruction of the name from the tokens,
+ * as well as generally useful {@code equals}, {@code hashCode}, and {@code toString} methods. For security
+ * and performance reasons, subclasses must implement {@link #lookupEquals(AbstractCallSiteDescriptor)},
+ * {@link #lookupHashCode()} and {@link #lookupToString()} methods.
+ * @param <T> The call site descriptor subclass
  */
-public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor {
+public abstract class AbstractCallSiteDescriptor<T extends AbstractCallSiteDescriptor<T>> implements CallSiteDescriptor {
 
     @Override
     public String getName() {
         return appendName(new StringBuilder(getNameLength())).toString();
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public boolean equals(final Object obj) {
-        return obj instanceof CallSiteDescriptor && equals((CallSiteDescriptor)obj);
+        return obj != null && obj.getClass() == getClass() && equalsInKind((T)obj);
     }
 
     /**
-     * Returns true if this call site descriptor is equal to the passed call site descriptor.
+     * Returns true if this call site descriptor is equal to the passed, non-null call site descriptor of the
+     * same class.
      * @param csd the other call site descriptor.
      * @return true if they are equal.
      */
-    public boolean equals(final CallSiteDescriptor csd) {
-        if(csd == null) {
-            return false;
-        }
+    protected boolean equalsInKind(final T csd) {
         if(csd == this) {
             return true;
         }
@@ -128,13 +130,32 @@
         if(!getMethodType().equals(csd.getMethodType())) {
             return false;
         }
-        return lookupsEqual(getLookup(), csd.getLookup());
+        return lookupEquals(csd);
+    }
+
+    /**
+     * Returns true if this call site descriptor's lookup is equal to the other call site descriptor's lookup.
+     * Typical implementation should try to obtain the other lookup directly without going through
+     * {@link #getLookup()} (e.g. directly using the implementation) and then delegate to
+     * {@link #lookupsEqual(MethodHandles.Lookup, MethodHandles.Lookup)}.
+     * @param other the other lookup
+     * @return true if the lookups are equal
+     */
+    protected abstract boolean lookupEquals(T other);
+
+    protected static boolean lookupsEqual(final Lookup l1, final Lookup l2) {
+        if(l1 == l2) {
+            return true;
+        }
+        if(l1.lookupClass() != l2.lookupClass()) {
+            return false;
+        }
+        return l1.lookupModes() == l2.lookupModes();
     }
 
     @Override
     public int hashCode() {
-        final MethodHandles.Lookup lookup = getLookup();
-        int h = lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
+        int h = lookupHashCode();
         final int c = getNameTokenCount();
         for(int i = 0; i < c; ++i) {
             h = h * 31 + getNameToken(i).hashCode();
@@ -142,14 +163,32 @@
         return h * 31 + getMethodType().hashCode();
     }
 
+    /**
+     * Return the hash code of this call site descriptor's {@link Lookup} object. Typical
+     * implementation should delegate to {@link #lookupHashCode(MethodHandles.Lookup)}.
+     * @return the hash code of this call site descriptor's {@link Lookup} object.
+     */
+    protected abstract int lookupHashCode();
+
+    protected static int lookupHashCode(final Lookup lookup) {
+        return lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
+    }
+
     @Override
     public String toString() {
         final String mt = getMethodType().toString();
-        final String l = getLookup().toString();
+        final String l = lookupToString();
         final StringBuilder b = new StringBuilder(l.length() + 1 + mt.length() + getNameLength());
         return appendName(b).append(mt).append("@").append(l).toString();
     }
 
+    /**
+     * Return a string representation of this call site descriptor's {@link Lookup} object. Typically will
+     * return {@link Lookup#toString()}.
+     * @return a string representation of this call site descriptor's {@link Lookup} object.
+     */
+    protected abstract String lookupToString();
+
     private int getNameLength() {
         final int c = getNameTokenCount();
         int l = 0;
@@ -167,14 +206,4 @@
         }
         return b;
     }
-
-    private static boolean lookupsEqual(final Lookup l1, final Lookup l2) {
-        if(l1 == l2) {
-            return true;
-        }
-        if(l1.lookupClass() != l2.lookupClass()) {
-            return false;
-        }
-        return l1.lookupModes() == l2.lookupModes();
-    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/SimpleCallSiteDescriptor.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/SimpleCallSiteDescriptor.java	Mon Oct 19 08:30:03 2015 +0200
@@ -83,18 +83,19 @@
 
 package jdk.internal.dynalink.support;
 
+import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
-import java.security.Permission;
 import java.util.Objects;
 import jdk.internal.dynalink.CallSiteDescriptor;
 
 /**
  * A simple implementation of the call site descriptor. It stores the lookup, the name, and the method type.
+  * Even if you roll your own implementation of {@link CallSiteDescriptor}, you might want to use
+  * {@link CallSiteDescriptor#checkLookup(MethodHandles.Lookup)} as a ready-made utility method to ensure you're handing
+  * out lookup objects securely.
  */
-public class SimpleCallSiteDescriptor extends AbstractCallSiteDescriptor {
-    private static final Permission GET_LOOKUP_PERMISSION = new RuntimePermission("dynalink.getLookup");
-
+public class SimpleCallSiteDescriptor extends AbstractCallSiteDescriptor<SimpleCallSiteDescriptor> {
     private final Lookup lookup;
     private final String[] tokenizedName;
     private final MethodType methodType;
@@ -138,11 +139,26 @@
 
     @Override
     public final Lookup getLookup() {
-        return lookup;
+        return CallSiteDescriptor.checkLookup(lookup);
     }
 
     @Override
     public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
         return new SimpleCallSiteDescriptor(lookup, tokenizedName, newMethodType);
     }
+
+    @Override
+    protected boolean lookupEquals(final SimpleCallSiteDescriptor other) {
+        return AbstractCallSiteDescriptor.lookupsEqual(lookup, other.lookup);
+    }
+
+    @Override
+    protected int lookupHashCode() {
+        return AbstractCallSiteDescriptor.lookupHashCode(lookup);
+    }
+
+    @Override
+    protected String lookupToString() {
+        return lookup.toString();
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Mon Oct 19 08:30:03 2015 +0200
@@ -29,10 +29,14 @@
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
 import java.lang.invoke.SwitchPoint;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -914,7 +918,7 @@
         } else if (data.isBuiltin() && "extend".equals(data.getName())) {
             // NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
             // current lookup as its "this" so it can do security-sensitive creation of adapter classes.
-            boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, type.parameterType(0), type.parameterType(1));
+            boundHandle = MH.dropArguments(MH.bindTo(callHandle, getLookupPrivileged(desc)), 0, type.parameterType(0), type.parameterType(1));
         } else if (scopeCall && needsWrappedThis()) {
             // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
             // (this, args...) => ([this], args...)
@@ -955,6 +959,12 @@
                 exceptionGuard);
     }
 
+    private static Lookup getLookupPrivileged(final CallSiteDescriptor desc) {
+        // NOTE: we'd rather not make NashornCallSiteDescriptor.getLookupPrivileged public.
+        return AccessController.doPrivileged((PrivilegedAction<Lookup>)()->desc.getLookup(), null,
+                CallSiteDescriptor.GET_LOOKUP_PERMISSION);
+    }
+
     private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
         final MethodType descType = desc.getMethodType();
         final int paramCount = descType.parameterCount();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java	Mon Oct 19 08:30:03 2015 +0200
@@ -95,7 +95,8 @@
         final String opName = hasFixedName ? (DYN_GET_METHOD_FIXED + descriptor.getNameToken(
                 CallSiteDescriptor.NAME_OPERAND)) : DYN_GET_METHOD;
 
-        final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(descriptor.getLookup(), opName,
+        final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(
+                NashornCallSiteDescriptor.getLookupPrivileged(descriptor), opName,
                 type.changeParameterType(0, adapterClass), 0);
 
         // Delegate to BeansLinker
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Mon Oct 19 08:30:03 2015 +0200
@@ -108,8 +108,9 @@
             if (name != null) {
                 final MethodType callType = desc.getMethodType();
                 // drop callee (Undefined ScriptFunction) and change the request to be dyn:callMethod:<name>
-                final NashornCallSiteDescriptor newDesc = NashornCallSiteDescriptor.get(desc.getLookup(),
-                        "dyn:callMethod:" + name, desc.getMethodType().dropParameterTypes(1, 2),
+                final NashornCallSiteDescriptor newDesc = NashornCallSiteDescriptor.get(
+                        NashornCallSiteDescriptor.getLookupPrivileged(desc), "dyn:callMethod:" + name,
+                        desc.getMethodType().dropParameterTypes(1, 2),
                         NashornCallSiteDescriptor.getFlags(desc));
                 final GuardedInvocation gi = getGuardedInvocation(beansLinker,
                         linkRequest.replaceArguments(newDesc, linkRequest.getArguments()),
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Mon Oct 19 08:30:03 2015 +0200
@@ -28,6 +28,8 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import jdk.internal.dynalink.CallSiteDescriptor;
@@ -40,7 +42,7 @@
  * we can have a more compact representation, as we know that we're always only using {@code "dyn:*"} operations; also
  * we're storing flags in an additional primitive field.
  */
-public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor {
+public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor<NashornCallSiteDescriptor> {
     /** Flags that the call site references a scope variable (it's an identifier reference or a var declaration, not a
      * property access expression. */
     public static final int CALLSITE_SCOPE         = 1 << 0;
@@ -199,12 +201,20 @@
 
     @Override
     public Lookup getLookup() {
-        return lookup;
+        return CallSiteDescriptor.checkLookup(lookup);
+    }
+
+    static Lookup getLookupPrivileged(final CallSiteDescriptor csd) {
+        if (csd instanceof NashornCallSiteDescriptor) {
+            return ((NashornCallSiteDescriptor)csd).lookup;
+        }
+        return AccessController.doPrivileged((PrivilegedAction<Lookup>)()->csd.getLookup(), null,
+                CallSiteDescriptor.GET_LOOKUP_PERMISSION);
     }
 
     @Override
-    public boolean equals(final CallSiteDescriptor csd) {
-        return super.equals(csd) && flags == getFlags(csd);
+    protected boolean equalsInKind(final NashornCallSiteDescriptor csd) {
+        return super.equalsInKind(csd) && flags == csd.flags;
     }
 
     @Override
@@ -444,7 +454,22 @@
 
     @Override
     public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
-        return get(getLookup(), operator, operand, newMethodType, flags);
+        return get(lookup, operator, operand, newMethodType, flags);
+    }
+
+
+    @Override
+    protected boolean lookupEquals(final NashornCallSiteDescriptor other) {
+        return AbstractCallSiteDescriptor.lookupsEqual(lookup, other.lookup);
     }
 
+    @Override
+    protected int lookupHashCode() {
+        return AbstractCallSiteDescriptor.lookupHashCode(lookup);
+    }
+
+    @Override
+    protected String lookupToString() {
+        return lookup.toString();
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Mon Oct 19 08:30:03 2015 +0200
@@ -171,14 +171,14 @@
         return null;
     }
 
-    private static java.lang.invoke.MethodHandles.Lookup getCurrentLookup() {
-        final LinkRequest currentRequest = AccessController.doPrivileged(new PrivilegedAction<LinkRequest>() {
+    private static MethodHandles.Lookup getCurrentLookup() {
+        return AccessController.doPrivileged(new PrivilegedAction<MethodHandles.Lookup>() {
             @Override
-            public LinkRequest run() {
-                return DynamicLinker.getCurrentLinkRequest();
+            public MethodHandles.Lookup run() {
+                final LinkRequest currentRequest = DynamicLinker.getCurrentLinkRequest();
+                return currentRequest == null ? MethodHandles.publicLookup() : currentRequest.getCallSiteDescriptor().getLookup();
             }
-        });
-        return currentRequest == null ? MethodHandles.publicLookup() : currentRequest.getCallSiteDescriptor().getLookup();
+        }, null, CallSiteDescriptor.GET_LOOKUP_PERMISSION, DynamicLinker.GET_CURRENT_LINK_REQUEST_PERMISSION);
     }
 
     /**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java	Mon Oct 19 08:23:03 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java	Mon Oct 19 08:30:03 2015 +0200
@@ -83,7 +83,7 @@
                 // Change this link request into a link request on the adapter class.
                 final Object[] args = request.getArguments();
                 args[0] = JavaAdapterFactory.getAdapterClassFor(new Class<?>[] { receiverClass }, null,
-                        linkRequest.getCallSiteDescriptor().getLookup());
+                        NashornCallSiteDescriptor.getLookupPrivileged(linkRequest.getCallSiteDescriptor()));
                 final LinkRequest adapterRequest = request.replaceArguments(request.getCallSiteDescriptor(), args);
                 final GuardedInvocation gi = checkNullConstructor(delegate(linkerServices, adapterRequest), receiverClass);
                 // Finally, modify the guard to test for the original abstract class.