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