jdk/src/share/classes/sun/dyn/util/VerifyAccess.java
changeset 8823 7cd28219a1e4
parent 8717 f75a1efb1412
parent 8822 8145ab9f5f86
child 8824 0762fa26f813
child 9033 a88f5656f05d
equal deleted inserted replaced
8717:f75a1efb1412 8823:7cd28219a1e4
     1 /*
       
     2  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.dyn.util;
       
    27 
       
    28 import java.lang.reflect.Modifier;
       
    29 import sun.dyn.MemberName;
       
    30 import sun.dyn.MethodHandleImpl;
       
    31 import sun.dyn.empty.Empty;
       
    32 import static java.lang.reflect.Modifier.*;
       
    33 
       
    34 /**
       
    35  * This class centralizes information about the JVM's linkage access control.
       
    36  * @author jrose
       
    37  */
       
    38 public class VerifyAccess {
       
    39 
       
    40     private VerifyAccess() { }  // cannot instantiate
       
    41 
       
    42     private static final int PACKAGE_ONLY = 0;
       
    43     private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
       
    44     private static final boolean ALLOW_NESTMATE_ACCESS = false;
       
    45 
       
    46     /**
       
    47      * Evaluate the JVM linkage rules for access to the given method
       
    48      * on behalf of a caller class which proposes to perform the access.
       
    49      * Return true if the caller class has privileges to invoke a method
       
    50      * or access a field with the given properties.
       
    51      * This requires an accessibility check of the referencing class,
       
    52      * plus an accessibility check of the member within the class,
       
    53      * which depends on the member's modifier flags.
       
    54      * <p>
       
    55      * The relevant properties include the defining class ({@code defc})
       
    56      * of the member, and its modifier flags ({@code mods}).
       
    57      * Also relevant is the class used to make the initial symbolic reference
       
    58      * to the member ({@code refc}).  If this latter class is not distinguished,
       
    59      * the defining class should be passed for both arguments ({@code defc == refc}).
       
    60      * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
       
    61      * A field or method R is accessible to a class or interface D if
       
    62      * and only if any of the following conditions is true:<ul>
       
    63      * <li>R is public.
       
    64      * <li>R is protected and is declared in a class C, and D is either
       
    65      *     a subclass of C or C itself.  Furthermore, if R is not
       
    66      *     static, then the symbolic reference to R must contain a
       
    67      *     symbolic reference to a class T, such that T is either a
       
    68      *     subclass of D, a superclass of D or D itself.
       
    69      * <li>R is either protected or has default access (that is,
       
    70      *     neither public nor protected nor private), and is declared
       
    71      *     by a class in the same runtime package as D.
       
    72      * <li>R is private and is declared in D.
       
    73      * </ul>
       
    74      * This discussion of access control omits a related restriction
       
    75      * on the target of a protected field access or method invocation
       
    76      * (the target must be of class D or a subtype of D). That
       
    77      * requirement is checked as part of the verification process
       
    78      * (5.4.1); it is not part of link-time access control.
       
    79      * @param refc the class used in the symbolic reference to the proposed member
       
    80      * @param defc the class in which the proposed member is actually defined
       
    81      * @param mods modifier flags for the proposed member
       
    82      * @param lookupClass the class for which the access check is being made
       
    83      * @return true iff the the accessing class can access such a member
       
    84      */
       
    85     public static boolean isMemberAccessible(Class<?> refc,  // symbolic ref class
       
    86                                              Class<?> defc,  // actual def class
       
    87                                              int      mods,  // actual member mods
       
    88                                              Class<?> lookupClass) {
       
    89         // Usually refc and defc are the same, but if they differ, verify them both.
       
    90         if (refc != defc) {
       
    91             if (!isClassAccessible(refc, lookupClass)) {
       
    92                 // Note that defc is verified in the switch below.
       
    93                 return false;
       
    94             }
       
    95             if ((mods & (ALL_ACCESS_MODES|STATIC)) == (PROTECTED|STATIC)) {
       
    96                 // Apply the special rules for refc here.
       
    97                 if (!isRelatedClass(refc, lookupClass))
       
    98                     return isSamePackage(defc, lookupClass);
       
    99                 // If refc == defc, the call to isPublicSuperClass will do
       
   100                 // the whole job, since in that case refc (as defc) will be
       
   101                 // a superclass of the lookup class.
       
   102             }
       
   103         }
       
   104         if (defc == lookupClass)
       
   105             return true;        // easy check; all self-access is OK
       
   106         switch (mods & ALL_ACCESS_MODES) {
       
   107         case PUBLIC:
       
   108             if (refc != defc)  return true;  // already checked above
       
   109             return isClassAccessible(refc, lookupClass);
       
   110         case PROTECTED:
       
   111             return isSamePackage(defc, lookupClass) || isPublicSuperClass(defc, lookupClass);
       
   112         case PACKAGE_ONLY:
       
   113             return isSamePackage(defc, lookupClass);
       
   114         case PRIVATE:
       
   115             // Loosened rules for privates follows access rules for inner classes.
       
   116             return (ALLOW_NESTMATE_ACCESS &&
       
   117                     isSamePackageMember(defc, lookupClass));
       
   118         default:
       
   119             throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
       
   120         }
       
   121     }
       
   122 
       
   123     static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) {
       
   124         return (refc == lookupClass ||
       
   125                 refc.isAssignableFrom(lookupClass) ||
       
   126                 lookupClass.isAssignableFrom(refc));
       
   127     }
       
   128 
       
   129     static boolean isPublicSuperClass(Class<?> defc, Class<?> lookupClass) {
       
   130         return isPublic(defc.getModifiers()) && defc.isAssignableFrom(lookupClass);
       
   131     }
       
   132 
       
   133     /**
       
   134      * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
       
   135      * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
       
   136      * A class or interface C is accessible to a class or interface D
       
   137      * if and only if either of the following conditions are true:<ul>
       
   138      * <li>C is public.
       
   139      * <li>C and D are members of the same runtime package.
       
   140      * </ul>
       
   141      * @param refc the symbolic reference class to which access is being checked (C)
       
   142      * @param lookupClass the class performing the lookup (D)
       
   143      */
       
   144     public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass) {
       
   145         int mods = refc.getModifiers();
       
   146         if (isPublic(mods))
       
   147             return true;
       
   148         if (isSamePackage(lookupClass, refc))
       
   149             return true;
       
   150         return false;
       
   151     }
       
   152 
       
   153     /**
       
   154      * Test if two classes have the same class loader and package qualifier.
       
   155      * @param class1
       
   156      * @param class2
       
   157      * @return whether they are in the same package
       
   158      */
       
   159     public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
       
   160         if (class1 == class2)
       
   161             return true;
       
   162         if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader()))
       
   163             return false;
       
   164         String name1 = class1.getName(), name2 = class2.getName();
       
   165         int dot = name1.lastIndexOf('.');
       
   166         if (dot != name2.lastIndexOf('.'))
       
   167             return false;
       
   168         for (int i = 0; i < dot; i++) {
       
   169             if (name1.charAt(i) != name2.charAt(i))
       
   170                 return false;
       
   171         }
       
   172         return true;
       
   173     }
       
   174 
       
   175     /**
       
   176      * Test if two classes are defined as part of the same package member (top-level class).
       
   177      * If this is true, they can share private access with each other.
       
   178      * @param class1
       
   179      * @param class2
       
   180      * @return whether they are identical or nested together
       
   181      */
       
   182     public static boolean isSamePackageMember(Class<?> class1, Class<?> class2) {
       
   183         if (class1 == class2)
       
   184             return true;
       
   185         if (!isSamePackage(class1, class2))
       
   186             return false;
       
   187         if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2))
       
   188             return false;
       
   189         return true;
       
   190     }
       
   191 
       
   192     private static Class<?> getOutermostEnclosingClass(Class<?> c) {
       
   193         Class<?> pkgmem = c;
       
   194         for (Class<?> enc = c; (enc = enc.getEnclosingClass()) != null; )
       
   195             pkgmem = enc;
       
   196         return pkgmem;
       
   197     }
       
   198 
       
   199     private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2) {
       
   200         if (loader1 == loader2 || loader1 == null || loader2 == null) {
       
   201             return true;
       
   202         }
       
   203         for (ClassLoader scan1 = loader1;
       
   204                 scan1 != null; scan1 = scan1.getParent()) {
       
   205             if (scan1 == loader2)  return true;
       
   206         }
       
   207         for (ClassLoader scan2 = loader2;
       
   208                 scan2 != null; scan2 = scan2.getParent()) {
       
   209             if (scan2 == loader1)  return true;
       
   210         }
       
   211         return false;
       
   212     }
       
   213 }