jdk/src/share/classes/sun/invoke/util/VerifyAccess.java
changeset 8822 8145ab9f5f86
parent 8821 2836ee97ee27
child 9752 88ab34b6da6d
equal deleted inserted replaced
8821:2836ee97ee27 8822:8145ab9f5f86
       
     1 /*
       
     2  * Copyright (c) 2008, 2011, 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.invoke.util;
       
    27 
       
    28 import java.lang.reflect.Modifier;
       
    29 import static java.lang.reflect.Modifier.*;
       
    30 
       
    31 /**
       
    32  * This class centralizes information about the JVM's linkage access control.
       
    33  * @author jrose
       
    34  */
       
    35 public class VerifyAccess {
       
    36 
       
    37     private VerifyAccess() { }  // cannot instantiate
       
    38 
       
    39     private static final int PACKAGE_ONLY = 0;
       
    40     private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
       
    41     private static final boolean ALLOW_NESTMATE_ACCESS = false;
       
    42 
       
    43     /**
       
    44      * Evaluate the JVM linkage rules for access to the given method
       
    45      * on behalf of a caller class which proposes to perform the access.
       
    46      * Return true if the caller class has privileges to invoke a method
       
    47      * or access a field with the given properties.
       
    48      * This requires an accessibility check of the referencing class,
       
    49      * plus an accessibility check of the member within the class,
       
    50      * which depends on the member's modifier flags.
       
    51      * <p>
       
    52      * The relevant properties include the defining class ({@code defc})
       
    53      * of the member, and its modifier flags ({@code mods}).
       
    54      * Also relevant is the class used to make the initial symbolic reference
       
    55      * to the member ({@code refc}).  If this latter class is not distinguished,
       
    56      * the defining class should be passed for both arguments ({@code defc == refc}).
       
    57      * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
       
    58      * A field or method R is accessible to a class or interface D if
       
    59      * and only if any of the following conditions is true:<ul>
       
    60      * <li>R is public.
       
    61      * <li>R is protected and is declared in a class C, and D is either
       
    62      *     a subclass of C or C itself.  Furthermore, if R is not
       
    63      *     static, then the symbolic reference to R must contain a
       
    64      *     symbolic reference to a class T, such that T is either a
       
    65      *     subclass of D, a superclass of D or D itself.
       
    66      * <li>R is either protected or has default access (that is,
       
    67      *     neither public nor protected nor private), and is declared
       
    68      *     by a class in the same runtime package as D.
       
    69      * <li>R is private and is declared in D.
       
    70      * </ul>
       
    71      * This discussion of access control omits a related restriction
       
    72      * on the target of a protected field access or method invocation
       
    73      * (the target must be of class D or a subtype of D). That
       
    74      * requirement is checked as part of the verification process
       
    75      * (5.4.1); it is not part of link-time access control.
       
    76      * @param refc the class used in the symbolic reference to the proposed member
       
    77      * @param defc the class in which the proposed member is actually defined
       
    78      * @param mods modifier flags for the proposed member
       
    79      * @param lookupClass the class for which the access check is being made
       
    80      * @return true iff the the accessing class can access such a member
       
    81      */
       
    82     public static boolean isMemberAccessible(Class<?> refc,  // symbolic ref class
       
    83                                              Class<?> defc,  // actual def class
       
    84                                              int      mods,  // actual member mods
       
    85                                              Class<?> lookupClass) {
       
    86         // Usually refc and defc are the same, but if they differ, verify them both.
       
    87         if (refc != defc) {
       
    88             if (!isClassAccessible(refc, lookupClass)) {
       
    89                 // Note that defc is verified in the switch below.
       
    90                 return false;
       
    91             }
       
    92             if ((mods & (ALL_ACCESS_MODES|STATIC)) == (PROTECTED|STATIC)) {
       
    93                 // Apply the special rules for refc here.
       
    94                 if (!isRelatedClass(refc, lookupClass))
       
    95                     return isSamePackage(defc, lookupClass);
       
    96                 // If refc == defc, the call to isPublicSuperClass will do
       
    97                 // the whole job, since in that case refc (as defc) will be
       
    98                 // a superclass of the lookup class.
       
    99             }
       
   100         }
       
   101         if (defc == lookupClass)
       
   102             return true;        // easy check; all self-access is OK
       
   103         switch (mods & ALL_ACCESS_MODES) {
       
   104         case PUBLIC:
       
   105             if (refc != defc)  return true;  // already checked above
       
   106             return isClassAccessible(refc, lookupClass);
       
   107         case PROTECTED:
       
   108             return isSamePackage(defc, lookupClass) || isPublicSuperClass(defc, lookupClass);
       
   109         case PACKAGE_ONLY:
       
   110             return isSamePackage(defc, lookupClass);
       
   111         case PRIVATE:
       
   112             // Loosened rules for privates follows access rules for inner classes.
       
   113             return (ALLOW_NESTMATE_ACCESS &&
       
   114                     isSamePackageMember(defc, lookupClass));
       
   115         default:
       
   116             throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
       
   117         }
       
   118     }
       
   119 
       
   120     static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) {
       
   121         return (refc == lookupClass ||
       
   122                 refc.isAssignableFrom(lookupClass) ||
       
   123                 lookupClass.isAssignableFrom(refc));
       
   124     }
       
   125 
       
   126     static boolean isPublicSuperClass(Class<?> defc, Class<?> lookupClass) {
       
   127         return isPublic(defc.getModifiers()) && defc.isAssignableFrom(lookupClass);
       
   128     }
       
   129 
       
   130     /**
       
   131      * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
       
   132      * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
       
   133      * A class or interface C is accessible to a class or interface D
       
   134      * if and only if either of the following conditions are true:<ul>
       
   135      * <li>C is public.
       
   136      * <li>C and D are members of the same runtime package.
       
   137      * </ul>
       
   138      * @param refc the symbolic reference class to which access is being checked (C)
       
   139      * @param lookupClass the class performing the lookup (D)
       
   140      */
       
   141     public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass) {
       
   142         int mods = refc.getModifiers();
       
   143         if (isPublic(mods))
       
   144             return true;
       
   145         if (isSamePackage(lookupClass, refc))
       
   146             return true;
       
   147         return false;
       
   148     }
       
   149 
       
   150     /**
       
   151      * Test if two classes have the same class loader and package qualifier.
       
   152      * @param class1
       
   153      * @param class2
       
   154      * @return whether they are in the same package
       
   155      */
       
   156     public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
       
   157         if (class1 == class2)
       
   158             return true;
       
   159         if (!loadersAreRelated(class1.getClassLoader(), class2.getClassLoader()))
       
   160             return false;
       
   161         String name1 = class1.getName(), name2 = class2.getName();
       
   162         int dot = name1.lastIndexOf('.');
       
   163         if (dot != name2.lastIndexOf('.'))
       
   164             return false;
       
   165         for (int i = 0; i < dot; i++) {
       
   166             if (name1.charAt(i) != name2.charAt(i))
       
   167                 return false;
       
   168         }
       
   169         return true;
       
   170     }
       
   171 
       
   172     /**
       
   173      * Test if two classes are defined as part of the same package member (top-level class).
       
   174      * If this is true, they can share private access with each other.
       
   175      * @param class1
       
   176      * @param class2
       
   177      * @return whether they are identical or nested together
       
   178      */
       
   179     public static boolean isSamePackageMember(Class<?> class1, Class<?> class2) {
       
   180         if (class1 == class2)
       
   181             return true;
       
   182         if (!isSamePackage(class1, class2))
       
   183             return false;
       
   184         if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2))
       
   185             return false;
       
   186         return true;
       
   187     }
       
   188 
       
   189     private static Class<?> getOutermostEnclosingClass(Class<?> c) {
       
   190         Class<?> pkgmem = c;
       
   191         for (Class<?> enc = c; (enc = enc.getEnclosingClass()) != null; )
       
   192             pkgmem = enc;
       
   193         return pkgmem;
       
   194     }
       
   195 
       
   196     private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2) {
       
   197         if (loader1 == loader2 || loader1 == null || loader2 == null) {
       
   198             return true;
       
   199         }
       
   200         for (ClassLoader scan1 = loader1;
       
   201                 scan1 != null; scan1 = scan1.getParent()) {
       
   202             if (scan1 == loader2)  return true;
       
   203         }
       
   204         for (ClassLoader scan2 = loader2;
       
   205                 scan2 != null; scan2 = scan2.getParent()) {
       
   206             if (scan2 == loader1)  return true;
       
   207         }
       
   208         return false;
       
   209     }
       
   210 }