1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 2005, 2013 Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 
28 package sun.reflect.misc;
29 import java.lang.reflect.Proxy;
30 
31 public final class ReflectUtil {
32 
ReflectUtil()33     private ReflectUtil() {
34     }
35 
forName(String name)36     public static Class forName(String name)
37         throws ClassNotFoundException {
38         checkPackageAccess(name);
39         return Class.forName(name);
40     }
41 
newInstance(Class cls)42     public static Object newInstance(Class cls)
43         throws InstantiationException, IllegalAccessException {
44         checkPackageAccess(cls);
45         return cls.newInstance();
46     }
47 
isSubclassOf(Class queryClass, Class ofClass)48     private static boolean isSubclassOf(Class queryClass,
49                                 Class ofClass)
50     {
51         while (queryClass != null) {
52             if (queryClass == ofClass) {
53                 return true;
54             }
55             queryClass = queryClass.getSuperclass();
56         }
57         return false;
58     }
59 
60     /**
61      * Checks package access on the given class.
62      *
63      * If it is a {@link Proxy#isProxyClass(java.lang.Class)} that implements
64      * a non-public interface (i.e. may be in a non-restricted package),
65      * also check the package access on the proxy interfaces.
66      */
checkPackageAccess(Class<?> clazz)67     public static void checkPackageAccess(Class<?> clazz) {
68         checkPackageAccess(clazz.getName());
69         if (isNonPublicProxyClass(clazz)) {
70             checkProxyPackageAccess(clazz);
71         }
72     }
73 
74     /**
75      * Checks package access on the given classname.
76      * This method is typically called when the Class instance is not
77      * available and the caller attempts to load a class on behalf
78      * the true caller (application).
79      */
checkPackageAccess(String name)80     public static void checkPackageAccess(String name) {
81         SecurityManager s = System.getSecurityManager();
82         if (s != null) {
83             String cname = name.replace('/', '.');
84             if (cname.startsWith("[")) {
85                 int b = cname.lastIndexOf('[') + 2;
86                 if (b > 1 && b < cname.length()) {
87                     cname = cname.substring(b);
88                 }
89             }
90             int i = cname.lastIndexOf('.');
91             if (i != -1) {
92                 s.checkPackageAccess(cname.substring(0, i));
93             }
94         }
95     }
96 
isPackageAccessible(Class clazz)97     public static boolean isPackageAccessible(Class clazz) {
98         try {
99             checkPackageAccess(clazz);
100         } catch (SecurityException e) {
101             return false;
102         }
103         return true;
104     }
105 
106     // Returns true if p is an ancestor of cl i.e. class loader 'p' can
107     // be found in the cl's delegation chain
isAncestor(ClassLoader p, ClassLoader cl)108     private static boolean isAncestor(ClassLoader p, ClassLoader cl) {
109         ClassLoader acl = cl;
110         do {
111             acl = acl.getParent();
112             if (p == acl) {
113                 return true;
114             }
115         } while (acl != null);
116         return false;
117     }
118 
119     /**
120      * Returns true if package access check is needed for reflective
121      * access from a class loader 'from' to classes or members in
122      * a class defined by class loader 'to'.  This method returns true
123      * if 'from' is not the same as or an ancestor of 'to'.  All code
124      * in a system domain are granted with all permission and so this
125      * method returns false if 'from' class loader is a class loader
126      * loading system classes.  On the other hand, if a class loader
127      * attempts to access system domain classes, it requires package
128      * access check and this method will return true.
129      */
needsPackageAccessCheck(ClassLoader from, ClassLoader to)130     public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) {
131         if (from == null || from == to)
132             return false;
133 
134         if (to == null)
135             return true;
136 
137         return !isAncestor(from, to);
138     }
139 
140     /**
141      * Check package access on the proxy interfaces that the given proxy class
142      * implements.
143      *
144      * @param clazz Proxy class object
145      */
checkProxyPackageAccess(Class<?> clazz)146     public static void checkProxyPackageAccess(Class<?> clazz) {
147         SecurityManager s = System.getSecurityManager();
148         if (s != null) {
149             // check proxy interfaces if the given class is a proxy class
150             if (Proxy.isProxyClass(clazz)) {
151                 for (Class<?> intf : clazz.getInterfaces()) {
152                     checkPackageAccess(intf);
153                 }
154             }
155         }
156     }
157 
158     /**
159      * Access check on the interfaces that a proxy class implements and throw
160      * {@code SecurityException} if it accesses a restricted package from
161      * the caller's class loader.
162      *
163      * @param ccl the caller's class loader
164      * @param interfaces the list of interfaces that a proxy class implements
165      */
checkProxyPackageAccess(ClassLoader ccl, Class<?>... interfaces)166     public static void checkProxyPackageAccess(ClassLoader ccl,
167                                                Class<?>... interfaces)
168     {
169         SecurityManager sm = System.getSecurityManager();
170         if (sm != null) {
171             for (Class<?> intf : interfaces) {
172                 ClassLoader cl = intf.getClassLoader();
173                 if (needsPackageAccessCheck(ccl, cl)) {
174                     checkPackageAccess(intf);
175                 }
176             }
177         }
178     }
179 
180     /**
181      * Test if the given class is a proxy class that implements
182      * non-public interface.  Such proxy class may be in a non-restricted
183      * package that bypasses checkPackageAccess.
184      */
isNonPublicProxyClass(Class<?> cls)185     public static boolean isNonPublicProxyClass(Class<?> cls) {
186         String name = cls.getName();
187         int i = name.lastIndexOf('.');
188         String pkg = (i != -1) ? name.substring(0, i) : "";
189 
190         // NOTE: Android creates proxies in the "default" package (and not com.sun.proxy), which
191         // makes this check imprecise. However, this function is only ever called if there's
192         // a security manager installed (which is the never case on android).
193         return Proxy.isProxyClass(cls) && !pkg.isEmpty();
194     }
195 }
196