Path: blob/master/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java
41159 views
/*1* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526package sun.reflect.misc;2728import java.lang.reflect.Member;29import java.lang.reflect.Method;30import java.lang.reflect.Modifier;31import java.lang.reflect.Proxy;32import jdk.internal.reflect.Reflection;33import sun.security.util.SecurityConstants;3435public final class ReflectUtil {3637private ReflectUtil() {38}3940public static Class<?> forName(String name)41throws ClassNotFoundException {42checkPackageAccess(name);43return Class.forName(name);44}4546/**47* Ensures that access to a method or field is granted and throws48* IllegalAccessException if not. This method is not suitable for checking49* access to constructors.50*51* @param currentClass the class performing the access52* @param memberClass the declaring class of the member being accessed53* @param target the target object if accessing instance field or method;54* or null if accessing static field or method or if target55* object access rights will be checked later56* @param modifiers the member's access modifiers57* @throws IllegalAccessException if access to member is denied58* @implNote Delegates directly to59* {@link Reflection#ensureMemberAccess(Class, Class, Class, int)}60* which should be used instead.61*/62public static void ensureMemberAccess(Class<?> currentClass,63Class<?> memberClass,64Object target,65int modifiers)66throws IllegalAccessException67{68Reflection.ensureMemberAccess(currentClass,69memberClass,70target == null ? null : target.getClass(),71modifiers);72}7374/**75* Does a conservative approximation of member access check. Use this if76* you don't have an actual 'userland' caller Class/ClassLoader available.77* This might be more restrictive than a precise member access check where78* you have a caller, but should never allow a member access that is79* forbidden.80*81* @param m the {@code Member} about to be accessed82*/83public static void conservativeCheckMemberAccess(Member m) throws SecurityException{84@SuppressWarnings("removal")85final SecurityManager sm = System.getSecurityManager();86if (sm == null)87return;8889// Check for package access on the declaring class.90//91// In addition, unless the member and the declaring class are both92// public check for access declared member permissions.93//94// This is done regardless of ClassLoader relations between the {@code95// Member m} and any potential caller.9697final Class<?> declaringClass = m.getDeclaringClass();9899privateCheckPackageAccess(sm, declaringClass);100101if (Modifier.isPublic(m.getModifiers()) &&102Modifier.isPublic(declaringClass.getModifiers()))103return;104105// Check for declared member access.106sm.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);107}108109/**110* Checks package access on the given class.111*112* If it is a {@link Proxy#isProxyClass(java.lang.Class)} that implements113* a non-public interface (i.e. may be in a non-restricted package),114* also check the package access on the proxy interfaces.115*/116public static void checkPackageAccess(Class<?> clazz) {117@SuppressWarnings("removal")118SecurityManager s = System.getSecurityManager();119if (s != null) {120privateCheckPackageAccess(s, clazz);121}122}123124/**125* NOTE: should only be called if a SecurityManager is installed126*/127private static void privateCheckPackageAccess(@SuppressWarnings("removal") SecurityManager s, Class<?> clazz) {128String pkg = clazz.getPackageName();129if (!pkg.isEmpty()) {130s.checkPackageAccess(pkg);131}132133if (isNonPublicProxyClass(clazz)) {134privateCheckProxyPackageAccess(s, clazz);135}136}137138/**139* Checks package access on the given classname.140* This method is typically called when the Class instance is not141* available and the caller attempts to load a class on behalf142* the true caller (application).143*/144public static void checkPackageAccess(String name) {145@SuppressWarnings("removal")146SecurityManager s = System.getSecurityManager();147if (s != null) {148String cname = name.replace('/', '.');149if (cname.startsWith("[")) {150int b = cname.lastIndexOf('[') + 2;151if (b > 1 && b < cname.length()) {152cname = cname.substring(b);153}154}155int i = cname.lastIndexOf('.');156if (i != -1) {157s.checkPackageAccess(cname.substring(0, i));158}159}160}161162public static boolean isPackageAccessible(Class<?> clazz) {163try {164checkPackageAccess(clazz);165} catch (SecurityException e) {166return false;167}168return true;169}170171// Returns true if p is an ancestor of cl i.e. class loader 'p' can172// be found in the cl's delegation chain173private static boolean isAncestor(ClassLoader p, ClassLoader cl) {174ClassLoader acl = cl;175do {176acl = acl.getParent();177if (p == acl) {178return true;179}180} while (acl != null);181return false;182}183184/**185* Returns true if package access check is needed for reflective186* access from a class loader 'from' to classes or members in187* a class defined by class loader 'to'. This method returns true188* if 'from' is not the same as or an ancestor of 'to'. All code189* in a system domain are granted with all permission and so this190* method returns false if 'from' class loader is a class loader191* loading system classes. On the other hand, if a class loader192* attempts to access system domain classes, it requires package193* access check and this method will return true.194*/195public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) {196if (from == null || from == to)197return false;198199if (to == null)200return true;201202return !isAncestor(from, to);203}204205/**206* Check package access on the proxy interfaces that the given proxy class207* implements.208*209* @param clazz Proxy class object210*/211public static void checkProxyPackageAccess(Class<?> clazz) {212@SuppressWarnings("removal")213SecurityManager s = System.getSecurityManager();214if (s != null) {215privateCheckProxyPackageAccess(s, clazz);216}217}218219/**220* NOTE: should only be called if a SecurityManager is installed221*/222private static void privateCheckProxyPackageAccess(@SuppressWarnings("removal") SecurityManager s, Class<?> clazz) {223// check proxy interfaces if the given class is a proxy class224if (Proxy.isProxyClass(clazz)) {225for (Class<?> intf : clazz.getInterfaces()) {226privateCheckPackageAccess(s, intf);227}228}229}230/**231* Access check on the interfaces that a proxy class implements and throw232* {@code SecurityException} if it accesses a restricted package from233* the caller's class loader.234*235* @param ccl the caller's class loader236* @param interfaces the list of interfaces that a proxy class implements237*/238public static void checkProxyPackageAccess(ClassLoader ccl,239Class<?>... interfaces)240{241@SuppressWarnings("removal")242SecurityManager sm = System.getSecurityManager();243if (sm != null) {244for (Class<?> intf : interfaces) {245ClassLoader cl = intf.getClassLoader();246if (needsPackageAccessCheck(ccl, cl)) {247privateCheckPackageAccess(sm, intf);248}249}250}251}252253// Note that bytecode instrumentation tools may exclude 'sun.*'254// classes but not generated proxy classes and so keep it in com.sun.*255public static final String PROXY_PACKAGE = "com.sun.proxy";256257/**258* Test if the given class is a proxy class that implements259* non-public interface. Such proxy class may be in a non-restricted260* package that bypasses checkPackageAccess.261*/262public static boolean isNonPublicProxyClass(Class<?> cls) {263if (!Proxy.isProxyClass(cls)) {264return false;265}266return !Modifier.isPublic(cls.getModifiers());267}268269/**270* Check if the given method is a method declared in the proxy interface271* implemented by the given proxy instance.272*273* @param proxy a proxy instance274* @param method an interface method dispatched to a InvocationHandler275*276* @throws IllegalArgumentException if the given proxy or method is invalid.277*/278public static void checkProxyMethod(Object proxy, Method method) {279// check if it is a valid proxy instance280if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) {281throw new IllegalArgumentException("Not a Proxy instance");282}283if (Modifier.isStatic(method.getModifiers())) {284throw new IllegalArgumentException("Can't handle static method");285}286287Class<?> c = method.getDeclaringClass();288if (c == Object.class) {289String name = method.getName();290if (name.equals("hashCode") || name.equals("equals") || name.equals("toString")) {291return;292}293}294295if (isSuperInterface(proxy.getClass(), c)) {296return;297}298299// disallow any method not declared in one of the proxy interfaces300throw new IllegalArgumentException("Can't handle: " + method);301}302303private static boolean isSuperInterface(Class<?> c, Class<?> intf) {304for (Class<?> i : c.getInterfaces()) {305if (i == intf) {306return true;307}308if (isSuperInterface(i, intf)) {309return true;310}311}312return false;313}314315}316317318