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