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 java.util.Arrays; 34 import sun.reflect.Reflection; 35 import sun.security.util.SecurityConstants; 36 37 public final class ReflectUtil { 38 39 private ReflectUtil() { 40 } 41 42 public static Class<?> forName(String name) 43 throws ClassNotFoundException { 44 checkPackageAccess(name); 45 return Class.forName(name); 46 } 47 48 public static Object newInstance(Class<?> cls) 49 throws InstantiationException, IllegalAccessException { 50 checkPackageAccess(cls); 51 return cls.newInstance(); 52 } 53 54 /* 55 * Reflection.ensureMemberAccess is overly-restrictive 56 * due to a bug. We awkwardly work around it for now. 57 */ 58 public static void ensureMemberAccess(Class<?> currentClass, 59 Class<?> memberClass, 60 Object target, 61 int modifiers) 62 throws IllegalAccessException 63 { 64 if (target == null && Modifier.isProtected(modifiers)) { 65 int mods = modifiers; 66 mods = mods & (~Modifier.PROTECTED); 67 mods = mods | Modifier.PUBLIC; 68 69 /* 70 * See if we fail because of class modifiers 71 */ 72 Reflection.ensureMemberAccess(currentClass, 73 memberClass, 74 target, 75 mods); 76 try { 77 /* 78 * We're still here so class access was ok. 79 * Now try with default field access. 80 */ 81 mods = mods & (~Modifier.PUBLIC); 82 Reflection.ensureMemberAccess(currentClass, 83 memberClass, 84 target, 85 mods); 86 /* 87 * We're still here so access is ok without 88 * checking for protected. 89 */ 90 return; 91 } catch (IllegalAccessException e) { 92 /* 93 * Access failed but we're 'protected' so 94 * if the test below succeeds then we're ok. 95 */ 96 if (isSubclassOf(currentClass, memberClass)) { 97 return; 98 } else { 99 throw e; 100 } 101 } 102 } else { 103 Reflection.ensureMemberAccess(currentClass, 104 memberClass, 105 target, 106 modifiers); 107 } 108 } 109 110 private static boolean isSubclassOf(Class<?> queryClass, 111 Class<?> ofClass) 112 { 113 while (queryClass != null) { 114 if (queryClass == ofClass) { 115 return true; 116 } 117 queryClass = queryClass.getSuperclass(); 118 } 119 return false; 120 } 121 122 /** 123 * Does a conservative approximation of member access check. Use this if 124 * you don't have an actual 'userland' caller Class/ClassLoader available. 125 * This might be more restrictive than a precise member access check where 126 * you have a caller, but should never allow a member access that is 127 * forbidden. 128 * 129 * @param m the {@code Member} about to be accessed 130 */ 131 public static void conservativeCheckMemberAccess(Member m) throws SecurityException{ 132 final SecurityManager sm = System.getSecurityManager(); 133 if (sm == null) 134 return; 135 136 // Check for package access on the declaring class. 137 // 138 // In addition, unless the member and the declaring class are both 139 // public check for access declared member permissions. 140 // 141 // This is done regardless of ClassLoader relations between the {@code 142 // Member m} and any potential caller. 143 144 final Class<?> declaringClass = m.getDeclaringClass(); 145 146 checkPackageAccess(declaringClass); 147 148 if (Modifier.isPublic(m.getModifiers()) && 149 Modifier.isPublic(declaringClass.getModifiers())) 150 return; 151 152 // Check for declared member access. 153 sm.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); 154 } 155 156 /** 157 * Checks package access on the given class. 158 * 159 * If it is a {@link Proxy#isProxyClass(java.lang.Class)} that implements 160 * a non-public interface (i.e. may be in a non-restricted package), 161 * also check the package access on the proxy interfaces. 162 */ 163 public static void checkPackageAccess(Class<?> clazz) { 164 checkPackageAccess(clazz.getName()); 165 if (isNonPublicProxyClass(clazz)) { 166 checkProxyPackageAccess(clazz); 167 } 168 } 169 170 /** 171 * Checks package access on the given classname. 172 * This method is typically called when the Class instance is not 173 * available and the caller attempts to load a class on behalf 174 * the true caller (application). 175 */ 176 public static void checkPackageAccess(String name) { 177 SecurityManager s = System.getSecurityManager(); 178 if (s != null) { 179 String cname = name.replace('/', '.'); 180 if (cname.startsWith("[")) { 181 int b = cname.lastIndexOf('[') + 2; 182 if (b > 1 && b < cname.length()) { 183 cname = cname.substring(b); 184 } 185 } 186 int i = cname.lastIndexOf('.'); 187 if (i != -1) { 188 s.checkPackageAccess(cname.substring(0, i)); 189 } 190 } 191 } 192 193 public static boolean isPackageAccessible(Class<?> clazz) { 194 try { 195 checkPackageAccess(clazz); 196 } catch (SecurityException e) { 197 return false; 198 } 199 return true; 200 } 201 202 // Returns true if p is an ancestor of cl i.e. class loader 'p' can 203 // be found in the cl's delegation chain 204 private static boolean isAncestor(ClassLoader p, ClassLoader cl) { 205 ClassLoader acl = cl; 206 do { 207 acl = acl.getParent(); 208 if (p == acl) { 209 return true; 210 } 211 } while (acl != null); 212 return false; 213 } 214 215 /** 216 * Returns true if package access check is needed for reflective 217 * access from a class loader 'from' to classes or members in 218 * a class defined by class loader 'to'. This method returns true 219 * if 'from' is not the same as or an ancestor of 'to'. All code 220 * in a system domain are granted with all permission and so this 221 * method returns false if 'from' class loader is a class loader 222 * loading system classes. On the other hand, if a class loader 223 * attempts to access system domain classes, it requires package 224 * access check and this method will return true. 225 */ 226 public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) { 227 if (from == null || from == to) 228 return false; 229 230 if (to == null) 231 return true; 232 233 return !isAncestor(from, to); 234 } 235 236 /** 237 * Check package access on the proxy interfaces that the given proxy class 238 * implements. 239 * 240 * @param clazz Proxy class object 241 */ 242 public static void checkProxyPackageAccess(Class<?> clazz) { 243 SecurityManager s = System.getSecurityManager(); 244 if (s != null) { 245 // check proxy interfaces if the given class is a proxy class 246 if (Proxy.isProxyClass(clazz)) { 247 for (Class<?> intf : clazz.getInterfaces()) { 248 checkPackageAccess(intf); 249 } 250 } 251 } 252 } 253 254 /** 255 * Access check on the interfaces that a proxy class implements and throw 256 * {@code SecurityException} if it accesses a restricted package from 257 * the caller's class loader. 258 * 259 * @param ccl the caller's class loader 260 * @param interfaces the list of interfaces that a proxy class implements 261 */ 262 public static void checkProxyPackageAccess(ClassLoader ccl, 263 Class<?>... interfaces) 264 { 265 SecurityManager sm = System.getSecurityManager(); 266 if (sm != null) { 267 for (Class<?> intf : interfaces) { 268 ClassLoader cl = intf.getClassLoader(); 269 if (needsPackageAccessCheck(ccl, cl)) { 270 checkPackageAccess(intf); 271 } 272 } 273 } 274 } 275 276 // Note that bytecode instrumentation tools may exclude 'sun.*' 277 // classes but not generated proxy classes and so keep it in com.sun.* 278 public static final String PROXY_PACKAGE = "com.sun.proxy"; 279 280 /** 281 * Test if the given class is a proxy class that implements 282 * non-public interface. Such proxy class may be in a non-restricted 283 * package that bypasses checkPackageAccess. 284 */ 285 public static boolean isNonPublicProxyClass(Class<?> cls) { 286 String name = cls.getName(); 287 int i = name.lastIndexOf('.'); 288 String pkg = (i != -1) ? name.substring(0, i) : ""; 289 return Proxy.isProxyClass(cls) && !pkg.equals(PROXY_PACKAGE); 290 } 291 292 /** 293 * Check if the given method is a method declared in the proxy interface 294 * implemented by the given proxy instance. 295 * 296 * @param proxy a proxy instance 297 * @param method an interface method dispatched to a InvocationHandler 298 * 299 * @throws IllegalArgumentException if the given proxy or method is invalid. 300 */ 301 public static void checkProxyMethod(Object proxy, Method method) { 302 // check if it is a valid proxy instance 303 if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) { 304 throw new IllegalArgumentException("Not a Proxy instance"); 305 } 306 if (Modifier.isStatic(method.getModifiers())) { 307 throw new IllegalArgumentException("Can't handle static method"); 308 } 309 310 Class<?> c = method.getDeclaringClass(); 311 if (c == Object.class) { 312 String name = method.getName(); 313 if (name.equals("hashCode") || name.equals("equals") || name.equals("toString")) { 314 return; 315 } 316 } 317 318 if (isSuperInterface(proxy.getClass(), c)) { 319 return; 320 } 321 322 // disallow any method not declared in one of the proxy interfaces 323 throw new IllegalArgumentException("Can't handle: " + method); 324 } 325 326 private static boolean isSuperInterface(Class<?> c, Class<?> intf) { 327 for (Class<?> i : c.getInterfaces()) { 328 if (i == intf) { 329 return true; 330 } 331 if (isSuperInterface(i, intf)) { 332 return true; 333 } 334 } 335 return false; 336 } 337 338 /** 339 * Checks if {@code Class cls} is a VM-anonymous class 340 * as defined by {@link jdk.internal.misc.Unsafe#defineAnonymousClass} 341 * (not to be confused with a Java Language anonymous inner class). 342 */ 343 public static boolean isVMAnonymousClass(Class<?> cls) { 344 return cls.getName().indexOf('/') > -1; 345 } 346 }