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 
30 import java.lang.reflect.Modifier;
31 import java.lang.reflect.Proxy;
32 import sun.reflect.Reflection;
33 
34 public final class ReflectUtil {
35 
ReflectUtil()36     private ReflectUtil() {
37     }
38 
forName(String name)39     public static Class<?> forName(String name)
40         throws ClassNotFoundException {
41         checkPackageAccess(name);
42         return Class.forName(name);
43     }
44 
newInstance(Class<?> cls)45     public static Object newInstance(Class<?> cls)
46         throws InstantiationException, IllegalAccessException {
47         checkPackageAccess(cls);
48         return cls.newInstance();
49     }
50 
51     /*
52      * Reflection.ensureMemberAccess is overly-restrictive
53      * due to a bug. We awkwardly work around it for now.
54      */
ensureMemberAccess(Class<?> currentClass, Class<?> memberClass, Object target, int modifiers)55     public static void ensureMemberAccess(Class<?> currentClass,
56                                           Class<?> memberClass,
57                                           Object target,
58                                           int modifiers)
59         throws IllegalAccessException
60     {
61         if (target == null && Modifier.isProtected(modifiers)) {
62             int mods = modifiers;
63             mods = mods & (~Modifier.PROTECTED);
64             mods = mods | Modifier.PUBLIC;
65 
66             /*
67              * See if we fail because of class modifiers
68              */
69             Reflection.ensureMemberAccess(currentClass,
70                                           memberClass,
71                                           target,
72                                           mods);
73             try {
74                 /*
75                  * We're still here so class access was ok.
76                  * Now try with default field access.
77                  */
78                 mods = mods & (~Modifier.PUBLIC);
79                 Reflection.ensureMemberAccess(currentClass,
80                                               memberClass,
81                                               target,
82                                               mods);
83                 /*
84                  * We're still here so access is ok without
85                  * checking for protected.
86                  */
87                 return;
88             } catch (IllegalAccessException e) {
89                 /*
90                  * Access failed but we're 'protected' so
91                  * if the test below succeeds then we're ok.
92                  */
93                 if (isSubclassOf(currentClass, memberClass)) {
94                     return;
95                 } else {
96                     throw e;
97                 }
98             }
99         } else {
100             Reflection.ensureMemberAccess(currentClass,
101                                           memberClass,
102                                           target,
103                                           modifiers);
104         }
105     }
106 
isSubclassOf(Class<?> queryClass, Class<?> ofClass)107     private static boolean isSubclassOf(Class<?> queryClass,
108                                         Class<?> ofClass)
109     {
110         while (queryClass != null) {
111             if (queryClass == ofClass) {
112                 return true;
113             }
114             queryClass = queryClass.getSuperclass();
115         }
116         return false;
117     }
118 
119     // Android-removed: Dead code: Unused method conservativeCheckMemberAccess().
120 
121     /**
122      * Checks package access on the given class.
123      *
124      * If it is a {@link Proxy#isProxyClass(java.lang.Class)} that implements
125      * a non-public interface (i.e. may be in a non-restricted package),
126      * also check the package access on the proxy interfaces.
127      */
checkPackageAccess(Class<?> clazz)128     public static void checkPackageAccess(Class<?> clazz) {
129         checkPackageAccess(clazz.getName());
130         if (isNonPublicProxyClass(clazz)) {
131             checkProxyPackageAccess(clazz);
132         }
133     }
134 
135     /**
136      * Checks package access on the given classname.
137      * This method is typically called when the Class instance is not
138      * available and the caller attempts to load a class on behalf
139      * the true caller (application).
140      */
checkPackageAccess(String name)141     public static void checkPackageAccess(String name) {
142         SecurityManager s = System.getSecurityManager();
143         if (s != null) {
144             String cname = name.replace('/', '.');
145             if (cname.startsWith("[")) {
146                 int b = cname.lastIndexOf('[') + 2;
147                 if (b > 1 && b < cname.length()) {
148                     cname = cname.substring(b);
149                 }
150             }
151             int i = cname.lastIndexOf('.');
152             if (i != -1) {
153                 s.checkPackageAccess(cname.substring(0, i));
154             }
155         }
156     }
157 
isPackageAccessible(Class<?> clazz)158     public static boolean isPackageAccessible(Class<?> clazz) {
159         try {
160             checkPackageAccess(clazz);
161         } catch (SecurityException e) {
162             return false;
163         }
164         return true;
165     }
166 
167     // Returns true if p is an ancestor of cl i.e. class loader 'p' can
168     // be found in the cl's delegation chain
isAncestor(ClassLoader p, ClassLoader cl)169     private static boolean isAncestor(ClassLoader p, ClassLoader cl) {
170         ClassLoader acl = cl;
171         do {
172             acl = acl.getParent();
173             if (p == acl) {
174                 return true;
175             }
176         } while (acl != null);
177         return false;
178     }
179 
180     /**
181      * Returns true if package access check is needed for reflective
182      * access from a class loader 'from' to classes or members in
183      * a class defined by class loader 'to'.  This method returns true
184      * if 'from' is not the same as or an ancestor of 'to'.  All code
185      * in a system domain are granted with all permission and so this
186      * method returns false if 'from' class loader is a class loader
187      * loading system classes.  On the other hand, if a class loader
188      * attempts to access system domain classes, it requires package
189      * access check and this method will return true.
190      */
needsPackageAccessCheck(ClassLoader from, ClassLoader to)191     public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) {
192         if (from == null || from == to)
193             return false;
194 
195         if (to == null)
196             return true;
197 
198         return !isAncestor(from, to);
199     }
200 
201     /**
202      * Check package access on the proxy interfaces that the given proxy class
203      * implements.
204      *
205      * @param clazz Proxy class object
206      */
checkProxyPackageAccess(Class<?> clazz)207     public static void checkProxyPackageAccess(Class<?> clazz) {
208         SecurityManager s = System.getSecurityManager();
209         if (s != null) {
210             // check proxy interfaces if the given class is a proxy class
211             if (Proxy.isProxyClass(clazz)) {
212                 for (Class<?> intf : clazz.getInterfaces()) {
213                     checkPackageAccess(intf);
214                 }
215             }
216         }
217     }
218 
219     /**
220      * Access check on the interfaces that a proxy class implements and throw
221      * {@code SecurityException} if it accesses a restricted package from
222      * the caller's class loader.
223      *
224      * @param ccl the caller's class loader
225      * @param interfaces the list of interfaces that a proxy class implements
226      */
checkProxyPackageAccess(ClassLoader ccl, Class<?>... interfaces)227     public static void checkProxyPackageAccess(ClassLoader ccl,
228                                                Class<?>... interfaces)
229     {
230         SecurityManager sm = System.getSecurityManager();
231         if (sm != null) {
232             for (Class<?> intf : interfaces) {
233                 ClassLoader cl = intf.getClassLoader();
234                 if (needsPackageAccessCheck(ccl, cl)) {
235                     checkPackageAccess(intf);
236                 }
237             }
238         }
239     }
240 
241     // Android-changed: Proxy classes are generated in the default package on Android.
242     /*
243     // Note that bytecode instrumentation tools may exclude 'sun.*'
244     // classes but not generated proxy classes and so keep it in com.sun.*
245     public static final String PROXY_PACKAGE = "com.sun.proxy";
246     */
247 
248     /**
249      * Test if the given class is a proxy class that implements
250      * non-public interface.  Such proxy class may be in a non-restricted
251      * package that bypasses checkPackageAccess.
252      */
isNonPublicProxyClass(Class<?> cls)253     public static boolean isNonPublicProxyClass(Class<?> cls) {
254         String name = cls.getName();
255         int i = name.lastIndexOf('.');
256         String pkg = (i != -1) ? name.substring(0, i) : "";
257         // Android-changed: Proxy classes are generated in the default package on Android.
258         // The use of the default package (as opposed to com.sun.proxy) makes this check
259         // imprecise. However, this function is only ever called if there's
260         // a security manager installed (which is the never case on Android).
261         // return Proxy.isProxyClass(cls) && !pkg.equals(PROXY_PACKAGE);
262         return Proxy.isProxyClass(cls) && !pkg.isEmpty();
263     }
264 
265     // Android-removed: Dead code: unused method checkProxyMethod().
266     // Android-removed: Dead code: unused method isVMAnonymousClass().
267 }
268