1 /*
   2  * Copyright (c) 2005, 2013, 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 
  27 package sun.reflect.misc;
  28 
  29 import java.lang.reflect.Member;
  30 import java.lang.reflect.Method;
  31 import java.lang.reflect.Modifier;
  32 import java.lang.reflect.Proxy;
  33 import jdk.internal.reflect.Reflection;
  34 import sun.security.util.SecurityConstants;
  35 
  36 public final class ReflectUtil {
  37 
  38     private ReflectUtil() {
  39     }
  40 
  41     public static Class<?> forName(String name)
  42         throws ClassNotFoundException {
  43         checkPackageAccess(name);
  44         return Class.forName(name);
  45     }
  46 
  47     /**
  48      * Ensures that access to a method or field is granted and throws
  49      * IllegalAccessException if not. This method is not suitable for checking
  50      * access to constructors.
  51      *
  52      * @param currentClass the class performing the access
  53      * @param memberClass the declaring class of the member being accessed
  54      * @param target the target object if accessing instance field or method;
  55      *               or null if accessing static field or method or if target
  56      *               object access rights will be checked later
  57      * @param modifiers the member's access modifiers
  58      * @throws IllegalAccessException if access to member is denied
  59      * @implNote Delegates directly to
  60      *           {@link Reflection#ensureMemberAccess(Class, Class, Class, int)}
  61      *           which should be used instead.
  62      */
  63     public static void ensureMemberAccess(Class<?> currentClass,
  64                                           Class<?> memberClass,
  65                                           Object target,
  66                                           int modifiers)
  67         throws IllegalAccessException
  68     {
  69         Reflection.ensureMemberAccess(currentClass,
  70                                       memberClass,
  71                                       target == null ? null : target.getClass(),
  72                                       modifiers);
  73     }
  74 
  75     /**
  76      * Does a conservative approximation of member access check. Use this if
  77      * you don't have an actual 'userland' caller Class/ClassLoader available.
  78      * This might be more restrictive than a precise member access check where
  79      * you have a caller, but should never allow a member access that is
  80      * forbidden.
  81      *
  82      * @param m the {@code Member} about to be accessed
  83      */
  84     public static void conservativeCheckMemberAccess(Member m) throws SecurityException{
  85         final SecurityManager sm = System.getSecurityManager();
  86         if (sm == null)
  87             return;
  88 
  89         // Check for package access on the declaring class.
  90         //
  91         // In addition, unless the member and the declaring class are both
  92         // public check for access declared member permissions.
  93         //
  94         // This is done regardless of ClassLoader relations between the {@code
  95         // Member m} and any potential caller.
  96 
  97         final Class<?> declaringClass = m.getDeclaringClass();
  98 
  99         checkPackageAccess(declaringClass);
 100 
 101         if (Modifier.isPublic(m.getModifiers()) &&
 102                 Modifier.isPublic(declaringClass.getModifiers()))
 103             return;
 104 
 105         // Check for declared member access.
 106         sm.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
 107     }
 108 
 109     /**
 110      * Checks package access on the given class.
 111      *
 112      * If it is a {@link Proxy#isProxyClass(java.lang.Class)} that implements
 113      * a non-public interface (i.e. may be in a non-restricted package),
 114      * also check the package access on the proxy interfaces.
 115      */
 116     public static void checkPackageAccess(Class<?> clazz) {
 117         checkPackageAccess(clazz.getName());
 118         if (isNonPublicProxyClass(clazz)) {
 119             checkProxyPackageAccess(clazz);
 120         }
 121     }
 122 
 123     /**
 124      * Checks package access on the given classname.
 125      * This method is typically called when the Class instance is not
 126      * available and the caller attempts to load a class on behalf
 127      * the true caller (application).
 128      */
 129     public static void checkPackageAccess(String name) {
 130         SecurityManager s = System.getSecurityManager();
 131         if (s != null) {
 132             String cname = name.replace('/', '.');
 133             if (cname.startsWith("[")) {
 134                 int b = cname.lastIndexOf('[') + 2;
 135                 if (b > 1 && b < cname.length()) {
 136                     cname = cname.substring(b);
 137                 }
 138             }
 139             int i = cname.lastIndexOf('.');
 140             if (i != -1) {
 141                 s.checkPackageAccess(cname.substring(0, i));
 142             }
 143         }
 144     }
 145 
 146     public static boolean isPackageAccessible(Class<?> clazz) {
 147         try {
 148             checkPackageAccess(clazz);
 149         } catch (SecurityException e) {
 150             return false;
 151         }
 152         return true;
 153     }
 154 
 155     // Returns true if p is an ancestor of cl i.e. class loader 'p' can
 156     // be found in the cl's delegation chain
 157     private static boolean isAncestor(ClassLoader p, ClassLoader cl) {
 158         ClassLoader acl = cl;
 159         do {
 160             acl = acl.getParent();
 161             if (p == acl) {
 162                 return true;
 163             }
 164         } while (acl != null);
 165         return false;
 166     }
 167 
 168     /**
 169      * Returns true if package access check is needed for reflective
 170      * access from a class loader 'from' to classes or members in
 171      * a class defined by class loader 'to'.  This method returns true
 172      * if 'from' is not the same as or an ancestor of 'to'.  All code
 173      * in a system domain are granted with all permission and so this
 174      * method returns false if 'from' class loader is a class loader
 175      * loading system classes.  On the other hand, if a class loader
 176      * attempts to access system domain classes, it requires package
 177      * access check and this method will return true.
 178      */
 179     public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) {
 180         if (from == null || from == to)
 181             return false;
 182 
 183         if (to == null)
 184             return true;
 185 
 186         return !isAncestor(from, to);
 187     }
 188 
 189     /**
 190      * Check package access on the proxy interfaces that the given proxy class
 191      * implements.
 192      *
 193      * @param clazz Proxy class object
 194      */
 195     public static void checkProxyPackageAccess(Class<?> clazz) {
 196         SecurityManager s = System.getSecurityManager();
 197         if (s != null) {
 198             // check proxy interfaces if the given class is a proxy class
 199             if (Proxy.isProxyClass(clazz)) {
 200                 for (Class<?> intf : clazz.getInterfaces()) {
 201                     checkPackageAccess(intf);
 202                 }
 203             }
 204         }
 205     }
 206 
 207     /**
 208      * Access check on the interfaces that a proxy class implements and throw
 209      * {@code SecurityException} if it accesses a restricted package from
 210      * the caller's class loader.
 211      *
 212      * @param ccl the caller's class loader
 213      * @param interfaces the list of interfaces that a proxy class implements
 214      */
 215     public static void checkProxyPackageAccess(ClassLoader ccl,
 216                                                Class<?>... interfaces)
 217     {
 218         SecurityManager sm = System.getSecurityManager();
 219         if (sm != null) {
 220             for (Class<?> intf : interfaces) {
 221                 ClassLoader cl = intf.getClassLoader();
 222                 if (needsPackageAccessCheck(ccl, cl)) {
 223                     checkPackageAccess(intf);
 224                 }
 225             }
 226         }
 227     }
 228 
 229     // Note that bytecode instrumentation tools may exclude 'sun.*'
 230     // classes but not generated proxy classes and so keep it in com.sun.*
 231     public static final String PROXY_PACKAGE = "com.sun.proxy";
 232 
 233     /**
 234      * Test if the given class is a proxy class that implements
 235      * non-public interface.  Such proxy class may be in a non-restricted
 236      * package that bypasses checkPackageAccess.
 237      */
 238     public static boolean isNonPublicProxyClass(Class<?> cls) {
 239         String name = cls.getName();
 240         int i = name.lastIndexOf('.');
 241         String pkg = (i != -1) ? name.substring(0, i) : "";
 242         return Proxy.isProxyClass(cls) && !pkg.startsWith(PROXY_PACKAGE);
 243     }
 244 
 245     /**
 246      * Check if the given method is a method declared in the proxy interface
 247      * implemented by the given proxy instance.
 248      *
 249      * @param proxy a proxy instance
 250      * @param method an interface method dispatched to a InvocationHandler
 251      *
 252      * @throws IllegalArgumentException if the given proxy or method is invalid.
 253      */
 254     public static void checkProxyMethod(Object proxy, Method method) {
 255         // check if it is a valid proxy instance
 256         if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) {
 257             throw new IllegalArgumentException("Not a Proxy instance");
 258 }
 259         if (Modifier.isStatic(method.getModifiers())) {
 260             throw new IllegalArgumentException("Can't handle static method");
 261         }
 262 
 263         Class<?> c = method.getDeclaringClass();
 264         if (c == Object.class) {
 265             String name = method.getName();
 266             if (name.equals("hashCode") || name.equals("equals") || name.equals("toString")) {
 267                 return;
 268             }
 269         }
 270 
 271         if (isSuperInterface(proxy.getClass(), c)) {
 272             return;
 273         }
 274 
 275         // disallow any method not declared in one of the proxy interfaces
 276         throw new IllegalArgumentException("Can't handle: " + method);
 277     }
 278 
 279     private static boolean isSuperInterface(Class<?> c, Class<?> intf) {
 280         for (Class<?> i : c.getInterfaces()) {
 281             if (i == intf) {
 282                 return true;
 283             }
 284             if (isSuperInterface(i, intf)) {
 285                 return true;
 286             }
 287         }
 288         return false;
 289     }
 290 
 291     /**
 292      * Checks if {@code Class cls} is a VM-anonymous class
 293      * as defined by {@link jdk.internal.misc.Unsafe#defineAnonymousClass}
 294      * (not to be confused with a Java Language anonymous inner class).
 295      */
 296     public static boolean isVMAnonymousClass(Class<?> cls) {
 297         return cls.getName().indexOf('/') > -1;
 298     }
 299 }