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 
ReflectUtil()38     private ReflectUtil() {
39     }
40 
forName(String name)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      */
ensureMemberAccess(Class<?> currentClass, Class<?> memberClass, Object target, int modifiers)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      */
conservativeCheckMemberAccess(Member m)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         privateCheckPackageAccess(sm, 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      */
checkPackageAccess(Class<?> clazz)116     public static void checkPackageAccess(Class<?> clazz) {
117         SecurityManager s = System.getSecurityManager();
118         if (s != null) {
119             privateCheckPackageAccess(s, clazz);
120         }
121     }
122 
123     /**
124      * NOTE: should only be called if a SecurityManager is installed
125      */
privateCheckPackageAccess(SecurityManager s, Class<?> clazz)126     private static void privateCheckPackageAccess(SecurityManager s, Class<?> clazz) {
127         while (clazz.isArray()) {
128             clazz = clazz.getComponentType();
129         }
130 
131         String pkg = clazz.getPackageName();
132         if (pkg != null && !pkg.isEmpty()) {
133             s.checkPackageAccess(pkg);
134         }
135 
136         if (isNonPublicProxyClass(clazz)) {
137             privateCheckProxyPackageAccess(s, clazz);
138         }
139     }
140 
141     /**
142      * Checks package access on the given classname.
143      * This method is typically called when the Class instance is not
144      * available and the caller attempts to load a class on behalf
145      * the true caller (application).
146      */
checkPackageAccess(String name)147     public static void checkPackageAccess(String name) {
148         SecurityManager s = System.getSecurityManager();
149         if (s != null) {
150             String cname = name.replace('/', '.');
151             if (cname.startsWith("[")) {
152                 int b = cname.lastIndexOf('[') + 2;
153                 if (b > 1 && b < cname.length()) {
154                     cname = cname.substring(b);
155                 }
156             }
157             int i = cname.lastIndexOf('.');
158             if (i != -1) {
159                 s.checkPackageAccess(cname.substring(0, i));
160             }
161         }
162     }
163 
isPackageAccessible(Class<?> clazz)164     public static boolean isPackageAccessible(Class<?> clazz) {
165         try {
166             checkPackageAccess(clazz);
167         } catch (SecurityException e) {
168             return false;
169         }
170         return true;
171     }
172 
173     // Returns true if p is an ancestor of cl i.e. class loader 'p' can
174     // be found in the cl's delegation chain
isAncestor(ClassLoader p, ClassLoader cl)175     private static boolean isAncestor(ClassLoader p, ClassLoader cl) {
176         ClassLoader acl = cl;
177         do {
178             acl = acl.getParent();
179             if (p == acl) {
180                 return true;
181             }
182         } while (acl != null);
183         return false;
184     }
185 
186     /**
187      * Returns true if package access check is needed for reflective
188      * access from a class loader 'from' to classes or members in
189      * a class defined by class loader 'to'.  This method returns true
190      * if 'from' is not the same as or an ancestor of 'to'.  All code
191      * in a system domain are granted with all permission and so this
192      * method returns false if 'from' class loader is a class loader
193      * loading system classes.  On the other hand, if a class loader
194      * attempts to access system domain classes, it requires package
195      * access check and this method will return true.
196      */
needsPackageAccessCheck(ClassLoader from, ClassLoader to)197     public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) {
198         if (from == null || from == to)
199             return false;
200 
201         if (to == null)
202             return true;
203 
204         return !isAncestor(from, to);
205     }
206 
207     /**
208      * Check package access on the proxy interfaces that the given proxy class
209      * implements.
210      *
211      * @param clazz Proxy class object
212      */
checkProxyPackageAccess(Class<?> clazz)213     public static void checkProxyPackageAccess(Class<?> clazz) {
214         SecurityManager s = System.getSecurityManager();
215         if (s != null) {
216             privateCheckProxyPackageAccess(s, clazz);
217         }
218     }
219 
220     /**
221      * NOTE: should only be called if a SecurityManager is installed
222      */
privateCheckProxyPackageAccess(SecurityManager s, Class<?> clazz)223     private static void privateCheckProxyPackageAccess(SecurityManager s, Class<?> clazz) {
224         // check proxy interfaces if the given class is a proxy class
225         if (Proxy.isProxyClass(clazz)) {
226             for (Class<?> intf : clazz.getInterfaces()) {
227                 privateCheckPackageAccess(s, intf);
228             }
229         }
230     }
231     /**
232      * Access check on the interfaces that a proxy class implements and throw
233      * {@code SecurityException} if it accesses a restricted package from
234      * the caller's class loader.
235      *
236      * @param ccl the caller's class loader
237      * @param interfaces the list of interfaces that a proxy class implements
238      */
checkProxyPackageAccess(ClassLoader ccl, Class<?>... interfaces)239     public static void checkProxyPackageAccess(ClassLoader ccl,
240                                                Class<?>... interfaces)
241     {
242         SecurityManager sm = System.getSecurityManager();
243         if (sm != null) {
244             for (Class<?> intf : interfaces) {
245                 ClassLoader cl = intf.getClassLoader();
246                 if (needsPackageAccessCheck(ccl, cl)) {
247                     privateCheckPackageAccess(sm, intf);
248                 }
249             }
250         }
251     }
252 
253     // Note that bytecode instrumentation tools may exclude 'sun.*'
254     // classes but not generated proxy classes and so keep it in com.sun.*
255     public static final String PROXY_PACKAGE = "com.sun.proxy";
256 
257     /**
258      * Test if the given class is a proxy class that implements
259      * non-public interface.  Such proxy class may be in a non-restricted
260      * package that bypasses checkPackageAccess.
261      */
isNonPublicProxyClass(Class<?> cls)262     public static boolean isNonPublicProxyClass(Class<?> cls) {
263         if (!Proxy.isProxyClass(cls)) {
264             return false;
265         }
266         String pkg = cls.getPackageName();
267         return pkg == null || !pkg.startsWith(PROXY_PACKAGE);
268     }
269 
270     /**
271      * Check if the given method is a method declared in the proxy interface
272      * implemented by the given proxy instance.
273      *
274      * @param proxy a proxy instance
275      * @param method an interface method dispatched to a InvocationHandler
276      *
277      * @throws IllegalArgumentException if the given proxy or method is invalid.
278      */
checkProxyMethod(Object proxy, Method method)279     public static void checkProxyMethod(Object proxy, Method method) {
280         // check if it is a valid proxy instance
281         if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) {
282             throw new IllegalArgumentException("Not a Proxy instance");
283         }
284         if (Modifier.isStatic(method.getModifiers())) {
285             throw new IllegalArgumentException("Can't handle static method");
286         }
287 
288         Class<?> c = method.getDeclaringClass();
289         if (c == Object.class) {
290             String name = method.getName();
291             if (name.equals("hashCode") || name.equals("equals") || name.equals("toString")) {
292                 return;
293             }
294         }
295 
296         if (isSuperInterface(proxy.getClass(), c)) {
297             return;
298         }
299 
300         // disallow any method not declared in one of the proxy interfaces
301         throw new IllegalArgumentException("Can't handle: " + method);
302     }
303 
isSuperInterface(Class<?> c, Class<?> intf)304     private static boolean isSuperInterface(Class<?> c, Class<?> intf) {
305         for (Class<?> i : c.getInterfaces()) {
306             if (i == intf) {
307                 return true;
308             }
309             if (isSuperInterface(i, intf)) {
310                 return true;
311             }
312         }
313         return false;
314     }
315 
316     /**
317      * Checks if {@code Class cls} is a VM-anonymous class
318      * as defined by {@link jdk.internal.misc.Unsafe#defineAnonymousClass}
319      * (not to be confused with a Java Language anonymous inner class).
320      */
isVMAnonymousClass(Class<?> cls)321     public static boolean isVMAnonymousClass(Class<?> cls) {
322         return cls.getName().indexOf('/') > -1;
323     }
324 }
325