1 /* 2 * Copyright (c) 2001, 2022, 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 package jdk.internal.reflect; 27 28 import java.lang.reflect.*; 29 import java.util.HashMap; 30 import java.util.Map; 31 import java.util.Objects; 32 import java.util.Set; 33 34 import jdk.internal.access.SharedSecrets; 35 import jdk.internal.misc.VM; 36 import jdk.internal.module.ModuleBootstrap; 37 import jdk.internal.vm.annotation.ForceInline; 38 import jdk.internal.vm.annotation.IntrinsicCandidate; 39 40 /** Common utility routines used by both java.lang and 41 java.lang.reflect */ 42 43 public class Reflection { 44 45 /** Used to filter out fields and methods from certain classes from public 46 view, where they are sensitive or they may contain VM-internal objects. 47 These Maps are updated very rarely. Rather than synchronize on 48 each access, we use copy-on-write */ 49 private static volatile Map<Class<?>, Set<String>> fieldFilterMap; 50 private static volatile Map<Class<?>, Set<String>> methodFilterMap; 51 private static final String WILDCARD = "*"; 52 public static final Set<String> ALL_MEMBERS = Set.of(WILDCARD); 53 54 static { 55 fieldFilterMap = Map.of( 56 Reflection.class, ALL_MEMBERS, 57 AccessibleObject.class, ALL_MEMBERS, 58 Class.class, Set.of("classLoader", "classData"), 59 ClassLoader.class, ALL_MEMBERS, 60 Constructor.class, ALL_MEMBERS, 61 Field.class, ALL_MEMBERS, 62 Method.class, ALL_MEMBERS, 63 Module.class, ALL_MEMBERS, 64 System.class, Set.of("security") 65 ); 66 methodFilterMap = Map.of(); 67 } 68 69 /** Returns the class of the caller of the method calling this method, 70 ignoring frames associated with java.lang.reflect.Method.invoke() 71 and its implementation. */ 72 @CallerSensitive 73 @IntrinsicCandidate 74 public static native Class<?> getCallerClass(); 75 76 /** Retrieves the access flags written to the class file. For 77 inner classes these flags may differ from those returned by 78 Class.getModifiers(), which searches the InnerClasses 79 attribute to find the source-level access flags. This is used 80 instead of Class.getModifiers() for run-time access checks due 81 to compatibility reasons; see 4471811. Only the values of the 82 low 13 bits (i.e., a mask of 0x1FFF) are guaranteed to be 83 valid. */ 84 @IntrinsicCandidate 85 public static native int getClassAccessFlags(Class<?> c); 86 87 88 /** 89 * Ensures that access to a member is granted and throws 90 * IllegalAccessException if not. 91 * 92 * @param currentClass the class performing the access 93 * @param memberClass the declaring class of the member being accessed 94 * @param targetClass the class of target object if accessing instance 95 * field or method; 96 * or the declaring class if accessing constructor; 97 * or null if accessing static field or method 98 * @param modifiers the member's access modifiers 99 * @throws IllegalAccessException if access to member is denied 100 */ 101 public static void ensureMemberAccess(Class<?> currentClass, 102 Class<?> memberClass, 103 Class<?> targetClass, 104 int modifiers) 105 throws IllegalAccessException 106 { 107 if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) { 108 throw newIllegalAccessException(currentClass, memberClass, targetClass, modifiers); 109 } 110 } 111 112 @ForceInline 113 public static void ensureNativeAccess(Class<?> currentClass, Class<?> owner, String methodName) { 114 // if there is no caller class, act as if the call came from unnamed module of system class loader 115 Module module = currentClass != null ? 116 currentClass.getModule() : 117 ClassLoader.getSystemClassLoader().getUnnamedModule(); 118 SharedSecrets.getJavaLangAccess().ensureNativeAccess(module, owner, methodName); 119 } 120 121 /** 122 * Verify access to a member and return {@code true} if it is granted. 123 * 124 * @param currentClass the class performing the access 125 * @param memberClass the declaring class of the member being accessed 126 * @param targetClass the class of target object if accessing instance 127 * field or method; 128 * or the declaring class if accessing constructor; 129 * or null if accessing static field or method 130 * @param modifiers the member's access modifiers 131 * @return {@code true} if access to member is granted 132 */ 133 public static boolean verifyMemberAccess(Class<?> currentClass, 134 Class<?> memberClass, 135 Class<?> targetClass, 136 int modifiers) 137 { 138 Objects.requireNonNull(currentClass); 139 Objects.requireNonNull(memberClass); 140 141 if (currentClass == memberClass) { 142 // Always succeeds 143 return true; 144 } 145 146 if (!verifyModuleAccess(currentClass.getModule(), memberClass)) { 147 return false; 148 } 149 150 boolean gotIsSameClassPackage = false; 151 boolean isSameClassPackage = false; 152 153 if (!Modifier.isPublic(getClassAccessFlags(memberClass))) { 154 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 155 gotIsSameClassPackage = true; 156 if (!isSameClassPackage) { 157 return false; 158 } 159 } 160 161 // At this point we know that currentClass can access memberClass. 162 163 if (Modifier.isPublic(modifiers)) { 164 return true; 165 } 166 167 // Check for nestmate access if member is private 168 if (Modifier.isPrivate(modifiers)) { 169 // Note: targetClass may be outside the nest, but that is okay 170 // as long as memberClass is in the nest. 171 if (areNestMates(currentClass, memberClass)) { 172 return true; 173 } 174 } 175 176 boolean successSoFar = false; 177 178 if (Modifier.isProtected(modifiers)) { 179 // See if currentClass is a subclass of memberClass 180 if (isSubclassOf(currentClass, memberClass)) { 181 successSoFar = true; 182 } 183 } 184 185 if (!successSoFar && !Modifier.isPrivate(modifiers)) { 186 if (!gotIsSameClassPackage) { 187 isSameClassPackage = isSameClassPackage(currentClass, 188 memberClass); 189 gotIsSameClassPackage = true; 190 } 191 192 if (isSameClassPackage) { 193 successSoFar = true; 194 } 195 } 196 197 if (!successSoFar) { 198 return false; 199 } 200 201 // Additional test for protected instance members 202 // and protected constructors: JLS 6.6.2 203 if (targetClass != null && Modifier.isProtected(modifiers) && 204 targetClass != currentClass) 205 { 206 if (!gotIsSameClassPackage) { 207 isSameClassPackage = isSameClassPackage(currentClass, memberClass); 208 gotIsSameClassPackage = true; 209 } 210 if (!isSameClassPackage) { 211 if (!isSubclassOf(targetClass, currentClass)) { 212 return false; 213 } 214 } 215 } 216 217 return true; 218 } 219 220 /* 221 * Verify if a member is public and memberClass is a public type 222 * in a package that is unconditionally exported and 223 * return {@code true} if it is granted. 224 * 225 * @param memberClass the declaring class of the member being accessed 226 * @param modifiers the member's access modifiers 227 * @return {@code true} if the member is public and in a publicly accessible type 228 */ 229 public static boolean verifyPublicMemberAccess(Class<?> memberClass, int modifiers) { 230 Module m = memberClass.getModule(); 231 return Modifier.isPublic(modifiers) 232 && m.isExported(memberClass.getPackageName()) 233 && Modifier.isPublic(Reflection.getClassAccessFlags(memberClass)); 234 } 235 236 /** 237 * Returns {@code true} if memberClass's module exports memberClass's 238 * package to currentModule. 239 */ 240 public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) { 241 Module memberModule = memberClass.getModule(); 242 if (currentModule == memberModule) { 243 // same module (named or unnamed) or both null if called 244 // before module system is initialized, which means we are 245 // dealing with java.base only. 246 return true; 247 } else { 248 String pkg = memberClass.getPackageName(); 249 return memberModule.isExported(pkg, currentModule); 250 } 251 } 252 253 /** 254 * Returns true if two classes in the same package. 255 */ 256 private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) { 257 if (c1.getClassLoader() != c2.getClassLoader()) 258 return false; 259 return Objects.equals(c1.getPackageName(), c2.getPackageName()); 260 } 261 262 static boolean isSubclassOf(Class<?> queryClass, 263 Class<?> ofClass) 264 { 265 while (queryClass != null) { 266 if (queryClass == ofClass) { 267 return true; 268 } 269 queryClass = queryClass.getSuperclass(); 270 } 271 return false; 272 } 273 274 // fieldNames must contain only interned Strings 275 public static synchronized void registerFieldsToFilter(Class<?> containingClass, 276 Set<String> fieldNames) { 277 fieldFilterMap = 278 registerFilter(fieldFilterMap, containingClass, fieldNames); 279 } 280 281 // methodNames must contain only interned Strings 282 public static synchronized void registerMethodsToFilter(Class<?> containingClass, 283 Set<String> methodNames) { 284 methodFilterMap = 285 registerFilter(methodFilterMap, containingClass, methodNames); 286 } 287 288 private static Map<Class<?>, Set<String>> registerFilter(Map<Class<?>, Set<String>> map, 289 Class<?> containingClass, 290 Set<String> names) { 291 if (map.get(containingClass) != null) { 292 throw new IllegalArgumentException 293 ("Filter already registered: " + containingClass); 294 } 295 map = new HashMap<>(map); 296 map.put(containingClass, Set.copyOf(names)); 297 return map; 298 } 299 300 public static Field[] filterFields(Class<?> containingClass, Field[] fields) { 301 if (fieldFilterMap == null) { 302 // Bootstrapping 303 return fields; 304 } 305 return (Field[])filter(fields, fieldFilterMap.get(containingClass)); 306 } 307 308 public static Method[] filterMethods(Class<?> containingClass, Method[] methods) { 309 if (methodFilterMap == null) { 310 // Bootstrapping 311 return methods; 312 } 313 return (Method[])filter(methods, methodFilterMap.get(containingClass)); 314 } 315 316 private static Member[] filter(Member[] members, Set<String> filteredNames) { 317 if ((filteredNames == null) || (members.length == 0)) { 318 return members; 319 } 320 Class<?> memberType = members[0].getClass(); 321 if (filteredNames.contains(WILDCARD)) { 322 return (Member[]) Array.newInstance(memberType, 0); 323 } 324 int numNewMembers = 0; 325 for (Member member : members) { 326 if (!filteredNames.contains(member.getName())) { 327 ++numNewMembers; 328 } 329 } 330 Member[] newMembers = (Member[])Array.newInstance(memberType, numNewMembers); 331 int destIdx = 0; 332 for (Member member : members) { 333 if (!filteredNames.contains(member.getName())) { 334 newMembers[destIdx++] = member; 335 } 336 } 337 return newMembers; 338 } 339 340 /** 341 * Tests if the given method is caller-sensitive and the declaring class 342 * is defined by either the bootstrap class loader or platform class loader. 343 */ 344 public static boolean isCallerSensitive(Method m) { 345 final ClassLoader loader = m.getDeclaringClass().getClassLoader(); 346 if (VM.isSystemDomainLoader(loader)) { 347 return m.isAnnotationPresent(CallerSensitive.class); 348 } 349 return false; 350 } 351 352 /* 353 * Tests if the given Field is a trusted final field and it cannot be 354 * modified reflectively regardless of the value of its accessible flag. 355 */ 356 public static boolean isTrustedFinalField(Field field) { 357 return SharedSecrets.getJavaLangReflectAccess().isTrustedFinalField(field); 358 } 359 360 /** 361 * Returns an IllegalAccessException with an exception message based on 362 * the access that is denied. 363 */ 364 public static IllegalAccessException newIllegalAccessException(Class<?> currentClass, 365 Class<?> memberClass, 366 Class<?> targetClass, 367 int modifiers) 368 { 369 if (currentClass == null) 370 return newIllegalAccessException(memberClass, modifiers); 371 372 String currentSuffix = ""; 373 String memberSuffix = ""; 374 Module m1 = currentClass.getModule(); 375 if (m1.isNamed()) 376 currentSuffix = " (in " + m1 + ")"; 377 Module m2 = memberClass.getModule(); 378 if (m2.isNamed()) 379 memberSuffix = " (in " + m2 + ")"; 380 381 String memberPackageName = memberClass.getPackageName(); 382 383 String msg = currentClass + currentSuffix + " cannot access "; 384 if (m2.isExported(memberPackageName, m1)) { 385 // module access okay so include the modifiers in the message 386 msg += "a member of " + memberClass + memberSuffix + msgSuffix(modifiers); 387 } else { 388 // module access failed 389 msg += memberClass + memberSuffix+ " because " 390 + m2 + " does not export " + memberPackageName; 391 if (m2.isNamed()) msg += " to " + m1; 392 } 393 394 return new IllegalAccessException(msg); 395 } 396 397 /** 398 * Returns an IllegalAccessException with an exception message where 399 * there is no caller frame. 400 */ 401 private static IllegalAccessException newIllegalAccessException(Class<?> memberClass, 402 int modifiers) 403 { 404 String memberSuffix = ""; 405 Module m2 = memberClass.getModule(); 406 if (m2.isNamed()) 407 memberSuffix = " (in " + m2 + ")"; 408 409 String memberPackageName = memberClass.getPackageName(); 410 411 String msg = "JNI attached native thread (null caller frame) cannot access "; 412 if (m2.isExported(memberPackageName)) { 413 // module access okay so include the modifiers in the message 414 msg += "a member of " + memberClass + memberSuffix + msgSuffix(modifiers); 415 } else { 416 // module access failed 417 msg += memberClass + memberSuffix+ " because " 418 + m2 + " does not export " + memberPackageName; 419 } 420 421 return new IllegalAccessException(msg); 422 } 423 424 private static String msgSuffix(int modifiers) { 425 boolean packageAccess = 426 ((Modifier.PRIVATE | 427 Modifier.PROTECTED | 428 Modifier.PUBLIC) & modifiers) == 0; 429 return packageAccess ? 430 " with package access" : 431 " with modifiers \"" + Modifier.toString(modifiers) + "\""; 432 } 433 434 /** 435 * Returns true if {@code currentClass} and {@code memberClass} 436 * are nestmates - that is, if they have the same nesthost as 437 * determined by the VM. 438 */ 439 public static native boolean areNestMates(Class<?> currentClass, 440 Class<?> memberClass); 441 }