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