jdk/src/share/classes/sun/dyn/util/VerifyAccess.java
changeset 5725 16c1792b2ee6
parent 5506 202f599c92aa
parent 5722 4ada807383c8
child 7555 a279ebc3b25c
equal deleted inserted replaced
5721:faedb20bdcbb 5725:16c1792b2ee6
    24  */
    24  */
    25 
    25 
    26 package sun.dyn.util;
    26 package sun.dyn.util;
    27 
    27 
    28 import java.dyn.LinkagePermission;
    28 import java.dyn.LinkagePermission;
    29 import java.dyn.MethodHandles.Lookup;
       
    30 import java.dyn.NoAccessException;
    29 import java.dyn.NoAccessException;
    31 import java.lang.reflect.Modifier;
    30 import java.lang.reflect.Modifier;
    32 import sun.dyn.MemberName;
    31 import sun.dyn.MemberName;
    33 import sun.dyn.MethodHandleImpl;
    32 import sun.dyn.MethodHandleImpl;
    34 import sun.dyn.empty.Empty;
    33 import sun.dyn.empty.Empty;
       
    34 import static java.lang.reflect.Modifier.*;
    35 
    35 
    36 /**
    36 /**
    37  * This class centralizes information about the JVM's linkage access control.
    37  * This class centralizes information about the JVM's linkage access control.
    38  * @author jrose
    38  * @author jrose
    39  */
    39  */
    40 public class VerifyAccess {
    40 public class VerifyAccess {
    41 
    41 
    42     private VerifyAccess() { }  // cannot instantiate
    42     private VerifyAccess() { }  // cannot instantiate
    43 
    43 
    44     /**
    44     private static final int PACKAGE_ONLY = 0;
    45      * Evaluate the JVM linkage rules for access to the given method on behalf of caller.
    45     private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
    46      * Return non-null if and only if the given accessing class has at least partial
    46 
    47      * privileges to invoke the given method.  The return value {@code Object.class}
    47     /**
    48      * denotes unlimited privileges.
    48      * Evaluate the JVM linkage rules for access to the given method
       
    49      * on behalf of a caller class which proposes to perform the access.
       
    50      * Return true if the caller class has privileges to invoke a method
       
    51      * or access a field with the given properties.
       
    52      * This requires an accessibility check of the referencing class,
       
    53      * plus an accessibility check of the member within the class,
       
    54      * which depends on the member's modifier flags.
    49      * <p>
    55      * <p>
    50      * Some circumstances require an additional check on the
    56      * The relevant properties include the defining class ({@code defc})
    51      * leading parameter (the receiver) of the method, if it is non-static.
    57      * of the member, and its modifier flags ({@code mods}).
    52      * In the case of {@code invokespecial} ({@code isSpecialInvoke} is true),
    58      * Also relevant is the class used to make the initial symbolic reference
    53      * the leading parameter must be the accessing class or a subclass.
    59      * to the member ({@code refc}).  If this latter class is not distinguished,
    54      * In the case of a call to a {@code protected} method outside the same
    60      * the defining class should be passed for both arguments ({@code defc == refc}).
    55      * package, the same constraint applies.
    61      * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
    56      * @param m the proposed callee
    62      * A field or method R is accessible to a class or interface D if
    57      * @param isSpecialInvoke if true, a non-static method m is checked as if for {@code invokespecial}
    63      * and only if any of the following conditions is true:<ul>
       
    64      * <li>R is public.
       
    65      * <li>R is protected and is declared in a class C, and D is either
       
    66      *     a subclass of C or C itself.  Furthermore, if R is not
       
    67      *     static, then the symbolic reference to R must contain a
       
    68      *     symbolic reference to a class T, such that T is either a
       
    69      *     subclass of D, a superclass of D or D itself.
       
    70      * <li>R is either protected or has default access (that is,
       
    71      *     neither public nor protected nor private), and is declared
       
    72      *     by a class in the same runtime package as D.
       
    73      * <li>R is private and is declared in D.
       
    74      * </ul>
       
    75      * This discussion of access control omits a related restriction
       
    76      * on the target of a protected field access or method invocation
       
    77      * (the target must be of class D or a subtype of D). That
       
    78      * requirement is checked as part of the verification process
       
    79      * (5.4.1); it is not part of link-time access control.
       
    80      * @param refc the class used in the symbolic reference to the proposed member
       
    81      * @param defc the class in which the proposed member is actually defined
       
    82      * @param mods modifier flags for the proposed member
    58      * @param lookupClass the class for which the access check is being made
    83      * @param lookupClass the class for which the access check is being made
    59      * @return null if the method is not accessible, else a receiver type constraint, else {@code Object.class}
    84      * @return true iff the the accessing class can access such a member
    60      */
    85      */
    61     public static Class<?> isAccessible(Class<?> defc, int mods,
    86     public static boolean isMemberAccessible(Class<?> refc,  // symbolic ref class
    62             Class<?> lookupClass, boolean isSpecialInvoke) {
    87                                              Class<?> defc,  // actual def class
    63         if (!isAccessible(defc, lookupClass))
    88                                              int      mods,  // actual member mods
    64             return null;
    89                                              Class<?> lookupClass) {
    65         Class<?> constraint = Object.class;
    90         // Usually refc and defc are the same, but if they differ, verify them both.
    66         if (isSpecialInvoke && !Modifier.isStatic(mods)) {
    91         if (refc != defc) {
    67             constraint = lookupClass;
    92             if (!isClassAccessible(refc, lookupClass)) {
    68         }
    93                 // Note that defc is verified in the switch below.
    69         if (Modifier.isPublic(mods))
    94                 return false;
    70             return constraint;
    95             }
    71         if (Modifier.isPrivate(mods))
    96             if ((mods & (ALL_ACCESS_MODES|STATIC)) == (PROTECTED|STATIC)) {
    72             return isSamePackageMember(defc, lookupClass) ? constraint : null;
    97                 // Apply the special rules for refc here.
    73         if (isSamePackage(defc, lookupClass))
    98                 if (!isRelatedClass(refc, lookupClass))
    74             return constraint;
    99                     return isSamePackage(defc, lookupClass);
    75         if (Modifier.isProtected(mods) && defc.isAssignableFrom(lookupClass))
   100                 // If refc == defc, the call to isPublicSuperClass will do
    76             return constraint;
   101                 // the whole job, since in that case refc (as defc) will be
    77         // else it is private or package scoped, and not close enough
   102                 // a superclass of the lookup class.
    78         return null;
   103             }
       
   104         }
       
   105         switch (mods & ALL_ACCESS_MODES) {
       
   106         case PUBLIC:
       
   107             if (refc != defc)  return true;  // already checked above
       
   108             return isClassAccessible(refc, lookupClass);
       
   109         case PROTECTED:
       
   110             return isSamePackage(defc, lookupClass) || isPublicSuperClass(defc, lookupClass);
       
   111         case PACKAGE_ONLY:
       
   112             return isSamePackage(defc, lookupClass);
       
   113         case PRIVATE:
       
   114             // Loosened rules for privates follows access rules for inner classes.
       
   115             return isSamePackageMember(defc, lookupClass);
       
   116         default:
       
   117             throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
       
   118         }
       
   119     }
       
   120 
       
   121     static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) {
       
   122         return (refc == lookupClass ||
       
   123                 refc.isAssignableFrom(lookupClass) ||
       
   124                 lookupClass.isAssignableFrom(refc));
       
   125     }
       
   126 
       
   127     static boolean isPublicSuperClass(Class<?> defc, Class<?> lookupClass) {
       
   128         return isPublic(defc.getModifiers()) && defc.isAssignableFrom(lookupClass);
    79     }
   129     }
    80 
   130 
    81     /**
   131     /**
    82      * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
   132      * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
    83      */
   133      * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
    84     public static boolean isAccessible(Class<?> refc, Class<?> lookupClass) {
   134      * A class or interface C is accessible to a class or interface D
       
   135      * if and only if either of the following conditions are true:<ul>
       
   136      * <li>C is public.
       
   137      * <li>C and D are members of the same runtime package.
       
   138      * </ul>
       
   139      */
       
   140     public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass) {
    85         int mods = refc.getModifiers();
   141         int mods = refc.getModifiers();
    86         if (Modifier.isPublic(mods))
   142         if (isPublic(mods))
    87             return true;
   143             return true;
    88         if (isSamePackage(lookupClass, refc))
   144         if (isSamePackage(lookupClass, refc))
    89             return true;
   145             return true;
    90         return false;
   146         return false;
    91     }
   147     }
   168         SecurityManager security = System.getSecurityManager();
   224         SecurityManager security = System.getSecurityManager();
   169         if (security == null)  return;  // open season
   225         if (security == null)  return;  // open season
   170         if (isSamePackage(requestingClass, subjectClass))  return;
   226         if (isSamePackage(requestingClass, subjectClass))  return;
   171         security.checkPermission(new LinkagePermission(permissionName, requestingClass));
   227         security.checkPermission(new LinkagePermission(permissionName, requestingClass));
   172     }
   228     }
   173 
       
   174     private static RuntimeException checkNameFailed(MemberName self, Lookup lookup, String comment) {
       
   175         return new NoAccessException("cannot access from "+lookup+": "+self.toString()+": "+comment);
       
   176     }
       
   177     public static void checkName(MemberName self, Lookup lookup) {
       
   178         Class<?> lc = lookup.lookupClass();
       
   179         if (lc == null)  return;  // lookup is privileged
       
   180         Class<?> dc = self.getDeclaringClass();
       
   181         int samepkg = 0;
       
   182         // First check the containing class.  Must be public or local.
       
   183         if (!Modifier.isPublic(dc.getModifiers())) {
       
   184             if (lc != Empty.class)
       
   185                 samepkg = (isSamePackage(dc, lc) ? 1 : -1);
       
   186             if (samepkg <= 0)
       
   187                 throw checkNameFailed(self, lookup, "class is not public");
       
   188         }
       
   189         // At this point dc is known to be accessible.
       
   190         if (self.isPublic()) {
       
   191             return;
       
   192         } else if (lc == Empty.class) {
       
   193             throw checkNameFailed(self, lookup, "member is not public");
       
   194         } else if (self.isProtected()) {
       
   195             if (dc.isAssignableFrom(lc))  return;
       
   196         } else if (self.isPrivate()) {
       
   197             if (isSamePackageMember(dc, lc))  return;
       
   198             throw checkNameFailed(self, lookup, "member is private");
       
   199         }
       
   200         // Fall-through handles the package-private and protected cases.
       
   201         if (samepkg == 0)
       
   202             samepkg = (isSamePackage(dc, lc) ? 1 : -1);
       
   203         if (samepkg > 0)  return;
       
   204         throw checkNameFailed(self, lookup,
       
   205                 self.isProtected() ? "member is protected" : "member is private to package");
       
   206     }
       
   207 }
   229 }