6839839: access checking logic is wrong at three points in MethodHandles
authorjrose
Tue, 12 May 2009 13:54:22 -0700
changeset 120229180ef374c8
parent 1201 2387e3b1994e
child 1203 2a5a1b269e89
6839839: access checking logic is wrong at three points in MethodHandles
Summary: point fixes to access checking logic
Reviewed-by: mr
src/share/classes/java/dyn/MethodHandles.java
src/share/classes/sun/dyn/DirectMethodHandle.java
src/share/classes/sun/dyn/MemberName.java
src/share/classes/sun/dyn/MethodHandleImpl.java
src/share/classes/sun/dyn/MethodHandleNatives.java
src/share/classes/sun/dyn/util/VerifyAccess.java
     1.1 --- a/src/share/classes/java/dyn/MethodHandles.java	Mon May 11 21:09:58 2009 -0700
     1.2 +++ b/src/share/classes/java/dyn/MethodHandles.java	Tue May 12 13:54:22 2009 -0700
     1.3 @@ -145,27 +145,30 @@
     1.4              this.lookupClass = lookupClass;
     1.5          }
     1.6  
     1.7 +        private static final Class<?> PUBLIC_ONLY = sun.dyn.empty.Empty.class;
     1.8 +
     1.9          /** Version of lookup which is trusted minimally.
    1.10           *  It can only be used to create method handles to
    1.11           *  publicly accessible members.
    1.12           */
    1.13 -        public static final Lookup PUBLIC_LOOKUP = new Lookup(null);
    1.14 +        public static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_ONLY);
    1.15  
    1.16          /** Package-private version of lookup which is trusted. */
    1.17 -        static final Lookup IMPL_LOOKUP = new Lookup(Access.class);
    1.18 +        static final Lookup IMPL_LOOKUP = new Lookup(null);
    1.19          static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); }
    1.20  
    1.21          private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
    1.22 -            if (lookupClass == null ||
    1.23 -                lookupClass == Access.class ||
    1.24 -                lookupClass.getName().startsWith("java.dyn."))
    1.25 +            String name = lookupClass.getName();
    1.26 +            if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn."))
    1.27                  throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
    1.28          }
    1.29  
    1.30          @Override
    1.31          public String toString() {
    1.32 +            if (lookupClass == PUBLIC_ONLY)
    1.33 +                return "public";
    1.34              if (lookupClass == null)
    1.35 -                return "public";
    1.36 +                return "privileged";
    1.37              return lookupClass.getName();
    1.38          }
    1.39  
    1.40 @@ -205,6 +208,13 @@
    1.41           * with the receiver type ({@code defc}) prepended.
    1.42           * The method and all its argument types must be accessible to the lookup class.
    1.43           * <p>
    1.44 +         * (<em>BUG NOTE:</em> The type {@code Object} may be prepended instead
    1.45 +         * of the receiver type, if the receiver type is not on the boot class path.
    1.46 +         * This is due to a temporary JVM limitation, in which MethodHandle
    1.47 +         * claims to be unable to access such classes.  To work around this
    1.48 +         * bug, use {@code convertArguments} to normalize the type of the leading
    1.49 +         * argument to a type on the boot class path, such as {@code Object}.)
    1.50 +         * <p>
    1.51           * When called, the handle will treat the first argument as a receiver
    1.52           * and dispatch on the receiver's type to determine which method
    1.53           * implementation to enter.
    1.54 @@ -253,8 +263,7 @@
    1.55              MemberName method = IMPL_NAMES.resolveOrFail(new MemberName(defc, name, type), false, specialCaller);
    1.56              checkStatic(false, method, lookupClass);
    1.57              if (name.equals("<init>")) {
    1.58 -                if (defc != specialCaller)
    1.59 -                    throw newNoAccessException("constructor must be local to lookup class", method, lookupClass);
    1.60 +                throw newNoAccessException("cannot directly invoke a constructor", method, null);
    1.61              } else if (defc.isInterface() || !defc.isAssignableFrom(specialCaller)) {
    1.62                  throw newNoAccessException("method must be in a superclass of lookup class", method, lookupClass);
    1.63              }
     2.1 --- a/src/share/classes/sun/dyn/DirectMethodHandle.java	Mon May 11 21:09:58 2009 -0700
     2.2 +++ b/src/share/classes/sun/dyn/DirectMethodHandle.java	Tue May 12 13:54:22 2009 -0700
     2.3 @@ -45,8 +45,6 @@
     2.4          if (!m.isResolved())
     2.5              throw new InternalError();
     2.6  
     2.7 -        // Null check and replace privilege token (as passed to JVM) with null.
     2.8 -        if (lookupClass.equals(Access.class))  lookupClass = null;
     2.9          MethodHandleNatives.init(this, (Object) m, doDispatch, lookupClass);
    2.10      }
    2.11  
     3.1 --- a/src/share/classes/sun/dyn/MemberName.java	Mon May 11 21:09:58 2009 -0700
     3.2 +++ b/src/share/classes/sun/dyn/MemberName.java	Tue May 12 13:54:22 2009 -0700
     3.3 @@ -450,7 +450,7 @@
     3.4              for (;;) {
     3.5                  int bufCount = MethodHandleNatives.getMembers(defc,
     3.6                          matchName, matchSig, matchFlags,
     3.7 -                        MethodHandleNatives.asNativeCaller(lookupClass),
     3.8 +                        lookupClass,
     3.9                          totalCount, buf);
    3.10                  if (bufCount <= buf.length) {
    3.11                      if (bufCount >= 0)
    3.12 @@ -487,14 +487,13 @@
    3.13              return result;
    3.14          }
    3.15          boolean resolveInPlace(MemberName m, boolean searchSupers, Class<?> lookupClass) {
    3.16 -            Class<?> caller = MethodHandleNatives.asNativeCaller(lookupClass);
    3.17 -            MethodHandleNatives.resolve(m, caller);
    3.18 +            MethodHandleNatives.resolve(m, lookupClass);
    3.19              if (m.isResolved())  return true;
    3.20              int matchFlags = m.flags | (searchSupers ? SEARCH_ALL_SUPERS : 0);
    3.21              String matchSig = m.getSignature();
    3.22              MemberName[] buf = { m };
    3.23              int n = MethodHandleNatives.getMembers(m.getDeclaringClass(),
    3.24 -                    m.getName(), matchSig, matchFlags, caller, 0, buf);
    3.25 +                    m.getName(), matchSig, matchFlags, lookupClass, 0, buf);
    3.26              if (n != 1)  return false;
    3.27              return m.isResolved();
    3.28          }
     4.1 --- a/src/share/classes/sun/dyn/MethodHandleImpl.java	Mon May 11 21:09:58 2009 -0700
     4.2 +++ b/src/share/classes/sun/dyn/MethodHandleImpl.java	Tue May 12 13:54:22 2009 -0700
     4.3 @@ -95,7 +95,7 @@
     4.4  
     4.5      public static void initLookup(Access token, Lookup lookup) {
     4.6          Access.check(token);
     4.7 -        if (IMPL_LOOKUP_INIT != null || lookup.lookupClass() != Access.class)
     4.8 +        if (IMPL_LOOKUP_INIT != null || lookup.lookupClass() != null)
     4.9              throw new InternalError();
    4.10          IMPL_LOOKUP_INIT = lookup;
    4.11      }
    4.12 @@ -144,19 +144,28 @@
    4.13              boolean doDispatch, Class<?> lookupClass) {
    4.14          Access.check(token);  // only trusted calls
    4.15          MethodType mtype = method.getMethodType();
    4.16 +        MethodType rtype = mtype;
    4.17          if (method.isStatic()) {
    4.18              doDispatch = false;
    4.19          } else {
    4.20              // adjust the advertised receiver type to be exactly the one requested
    4.21              // (in the case of invokespecial, this will be the calling class)
    4.22 -            mtype = mtype.insertParameterType(0, method.getDeclaringClass());
    4.23 +            Class<?> recvType = method.getDeclaringClass();
    4.24 +            mtype = mtype.insertParameterType(0, recvType);
    4.25              if (method.isConstructor())
    4.26                  doDispatch = true;
    4.27 +            // FIXME: JVM has trouble building MH.invoke sites for
    4.28 +            // classes off the boot class path
    4.29 +            rtype = mtype;
    4.30 +            if (recvType.getClassLoader() != null)
    4.31 +                rtype = rtype.changeParameterType(0, Object.class);
    4.32          }
    4.33          DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
    4.34          if (!mh.isValid())
    4.35              throw newNoAccessException(method, lookupClass);
    4.36 -        return mh;
    4.37 +        MethodHandle rmh = AdapterMethodHandle.makePairwiseConvert(token, rtype, mh);
    4.38 +        if (rmh == null)  throw new InternalError();
    4.39 +        return rmh;
    4.40      }
    4.41  
    4.42      public static
    4.43 @@ -189,6 +198,15 @@
    4.44      MethodHandle bindReceiver(Access token,
    4.45                                MethodHandle target, Object receiver) {
    4.46          Access.check(token);
    4.47 +        if (target instanceof AdapterMethodHandle) {
    4.48 +            Object info = MethodHandleNatives.getTargetInfo(target);
    4.49 +            if (info instanceof DirectMethodHandle) {
    4.50 +                DirectMethodHandle dmh = (DirectMethodHandle) info;
    4.51 +                if (receiver == null ||
    4.52 +                    dmh.type().parameterType(0).isAssignableFrom(receiver.getClass()))
    4.53 +                    target = dmh;
    4.54 +            }
    4.55 +        }
    4.56          if (target instanceof DirectMethodHandle)
    4.57              return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
    4.58          return null;   // let caller try something else
     5.1 --- a/src/share/classes/sun/dyn/MethodHandleNatives.java	Mon May 11 21:09:58 2009 -0700
     5.2 +++ b/src/share/classes/sun/dyn/MethodHandleNatives.java	Tue May 12 13:54:22 2009 -0700
     5.3 @@ -47,14 +47,6 @@
     5.4      static native int getMembers(Class<?> defc, String matchName, String matchSig,
     5.5              int matchFlags, Class<?> caller, int skip, MemberName[] results);
     5.6  
     5.7 -    static Class<?> asNativeCaller(Class<?> lookupClass) {
     5.8 -        if (lookupClass == null)  // means "public only, non-privileged"
     5.9 -            return sun.dyn.empty.Empty.class;
    5.10 -        if (lookupClass == Access.class)  // means "internal, privileged"
    5.11 -            return null;    // to the JVM, null means completely privileged
    5.12 -        return lookupClass;
    5.13 -    }
    5.14 -
    5.15      /// MethodHandle support
    5.16  
    5.17      /** Initialize the method handle to adapt the call. */
     6.1 --- a/src/share/classes/sun/dyn/util/VerifyAccess.java	Mon May 11 21:09:58 2009 -0700
     6.2 +++ b/src/share/classes/sun/dyn/util/VerifyAccess.java	Tue May 12 13:54:22 2009 -0700
     6.3 @@ -95,7 +95,7 @@
     6.4      public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
     6.5          if (class1 == class2)
     6.6              return true;
     6.7 -        if (loadersAreRelated(class1.getClassLoader(), class2.getClassLoader()))
     6.8 +        if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader()))
     6.9              return false;
    6.10          String name1 = class1.getName(), name2 = class2.getName();
    6.11          int dot = name1.lastIndexOf('.');
    6.12 @@ -159,7 +159,7 @@
    6.13       */
    6.14      public static void checkBootstrapPrivilege(Class requestingClass, Class subjectClass,
    6.15                                                 String permissionName) {
    6.16 -        if (requestingClass == Access.class)  return;
    6.17 +        if (requestingClass == null)          return;
    6.18          if (requestingClass == subjectClass)  return;
    6.19          SecurityManager security = System.getSecurityManager();
    6.20          if (security == null)  return;  // open season