26 package java.lang.reflect; |
26 package java.lang.reflect; |
27 |
27 |
28 import java.lang.annotation.Annotation; |
28 import java.lang.annotation.Annotation; |
29 import java.security.AccessController; |
29 import java.security.AccessController; |
30 |
30 |
|
31 import jdk.internal.misc.VM; |
|
32 import jdk.internal.module.IllegalAccessLogger; |
31 import jdk.internal.reflect.CallerSensitive; |
33 import jdk.internal.reflect.CallerSensitive; |
32 import jdk.internal.reflect.Reflection; |
34 import jdk.internal.reflect.Reflection; |
33 import jdk.internal.reflect.ReflectionFactory; |
35 import jdk.internal.reflect.ReflectionFactory; |
|
36 import sun.security.action.GetPropertyAction; |
34 |
37 |
35 /** |
38 /** |
36 * The {@code AccessibleObject} class is the base class for {@code Field}, |
39 * The {@code AccessibleObject} class is the base class for {@code Field}, |
37 * {@code Method}, and {@code Constructor} objects (known as <em>reflected |
40 * {@code Method}, and {@code Constructor} objects (known as <em>reflected |
38 * objects</em>). It provides the ability to flag a reflected object as |
41 * objects</em>). It provides the ability to flag a reflected object as |
286 |
289 |
287 if (callerModule == declaringModule) return true; |
290 if (callerModule == declaringModule) return true; |
288 if (callerModule == Object.class.getModule()) return true; |
291 if (callerModule == Object.class.getModule()) return true; |
289 if (!declaringModule.isNamed()) return true; |
292 if (!declaringModule.isNamed()) return true; |
290 |
293 |
291 // package is open to caller |
294 String pn = declaringClass.getPackageName(); |
292 String pn = packageName(declaringClass); |
|
293 if (declaringModule.isOpen(pn, callerModule)) { |
|
294 dumpStackIfOpenedReflectively(declaringModule, pn, callerModule); |
|
295 return true; |
|
296 } |
|
297 |
|
298 // package is exported to caller |
|
299 boolean isExported = declaringModule.isExported(pn, callerModule); |
|
300 boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); |
|
301 int modifiers; |
295 int modifiers; |
302 if (this instanceof Executable) { |
296 if (this instanceof Executable) { |
303 modifiers = ((Executable) this).getModifiers(); |
297 modifiers = ((Executable) this).getModifiers(); |
304 } else { |
298 } else { |
305 modifiers = ((Field) this).getModifiers(); |
299 modifiers = ((Field) this).getModifiers(); |
306 } |
300 } |
307 if (isExported && isClassPublic) { |
301 |
308 |
302 // class is public and package is exported to caller |
|
303 boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers()); |
|
304 if (isClassPublic && declaringModule.isExported(pn, callerModule)) { |
309 // member is public |
305 // member is public |
310 if (Modifier.isPublic(modifiers)) { |
306 if (Modifier.isPublic(modifiers)) { |
311 dumpStackIfExportedReflectively(declaringModule, pn, callerModule); |
307 logIfExportedByBackdoor(caller, declaringClass); |
312 return true; |
308 return true; |
313 } |
309 } |
314 |
310 |
315 // member is protected-static |
311 // member is protected-static |
316 if (Modifier.isProtected(modifiers) |
312 if (Modifier.isProtected(modifiers) |
317 && Modifier.isStatic(modifiers) |
313 && Modifier.isStatic(modifiers) |
318 && isSubclassOf(caller, declaringClass)) { |
314 && isSubclassOf(caller, declaringClass)) { |
319 dumpStackIfExportedReflectively(declaringModule, pn, callerModule); |
315 logIfExportedByBackdoor(caller, declaringClass); |
320 return true; |
316 return true; |
321 } |
317 } |
|
318 } |
|
319 |
|
320 // package is open to caller |
|
321 if (declaringModule.isOpen(pn, callerModule)) { |
|
322 logIfOpenedByBackdoor(caller, declaringClass); |
|
323 return true; |
322 } |
324 } |
323 |
325 |
324 if (throwExceptionIfDenied) { |
326 if (throwExceptionIfDenied) { |
325 // not accessible |
327 // not accessible |
326 String msg = "Unable to make "; |
328 String msg = "Unable to make "; |
349 queryClass = queryClass.getSuperclass(); |
351 queryClass = queryClass.getSuperclass(); |
350 } |
352 } |
351 return false; |
353 return false; |
352 } |
354 } |
353 |
355 |
354 private void dumpStackIfOpenedReflectively(Module module, |
356 private void logIfOpenedByBackdoor(Class<?> caller, Class<?> declaringClass) { |
355 String pn, |
357 Module callerModule = caller.getModule(); |
356 Module other) { |
358 Module targetModule = declaringClass.getModule(); |
357 dumpStackIfExposedReflectively(module, pn, other, true); |
359 // callerModule is null during early startup |
358 } |
360 if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) { |
359 |
361 IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger(); |
360 private void dumpStackIfExportedReflectively(Module module, |
362 if (logger != null) { |
361 String pn, |
363 logger.logIfOpenedByBackdoor(caller, declaringClass, this::toShortString); |
362 Module other) { |
364 } |
363 dumpStackIfExposedReflectively(module, pn, other, false); |
365 } |
364 } |
366 } |
365 |
367 |
366 private void dumpStackIfExposedReflectively(Module module, |
368 private void logIfExportedByBackdoor(Class<?> caller, Class<?> declaringClass) { |
367 String pn, |
369 Module callerModule = caller.getModule(); |
368 Module other, |
370 Module targetModule = declaringClass.getModule(); |
369 boolean open) |
371 // callerModule is null during early startup |
370 { |
372 if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) { |
371 if (Reflection.printStackTraceWhenAccessSucceeds() |
373 IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger(); |
372 && !module.isStaticallyExportedOrOpen(pn, other, open)) |
374 if (logger != null) { |
373 { |
375 logger.logIfExportedByBackdoor(caller, declaringClass, this::toShortString); |
374 String msg = other + " allowed to invoke setAccessible on "; |
376 } |
375 if (this instanceof Field) |
377 } |
376 msg += "field "; |
378 } |
377 msg += this; |
379 |
378 new Exception(msg) { |
380 /** |
379 private static final long serialVersionUID = 42L; |
381 * Returns a short descriptive string to describe this object in log messages. |
380 public String toString() { |
382 */ |
381 return "WARNING: " + getMessage(); |
383 String toShortString() { |
382 } |
384 return toString(); |
383 }.printStackTrace(System.err); |
|
384 } |
|
385 } |
|
386 |
|
387 /** |
|
388 * Returns the package name of the given class. |
|
389 */ |
|
390 private static String packageName(Class<?> c) { |
|
391 while (c.isArray()) { |
|
392 c = c.getComponentType(); |
|
393 } |
|
394 String pn = c.getPackageName(); |
|
395 return (pn != null) ? pn : ""; |
|
396 } |
385 } |
397 |
386 |
398 /** |
387 /** |
399 * Get the value of the {@code accessible} flag for this reflected object. |
388 * Get the value of the {@code accessible} flag for this reflected object. |
400 * |
389 * |
596 |
583 |
597 final void checkAccess(Class<?> caller, Class<?> memberClass, |
584 final void checkAccess(Class<?> caller, Class<?> memberClass, |
598 Class<?> targetClass, int modifiers) |
585 Class<?> targetClass, int modifiers) |
599 throws IllegalAccessException |
586 throws IllegalAccessException |
600 { |
587 { |
|
588 if (!verifyAccess(caller, memberClass, targetClass, modifiers)) { |
|
589 IllegalAccessException e = Reflection.newIllegalAccessException( |
|
590 caller, memberClass, targetClass, modifiers); |
|
591 if (printStackTraceWhenAccessFails()) { |
|
592 e.printStackTrace(System.err); |
|
593 } |
|
594 throw e; |
|
595 } |
|
596 } |
|
597 |
|
598 final boolean verifyAccess(Class<?> caller, Class<?> memberClass, |
|
599 Class<?> targetClass, int modifiers) |
|
600 { |
601 if (caller == memberClass) { // quick check |
601 if (caller == memberClass) { // quick check |
602 return; // ACCESS IS OK |
602 return true; // ACCESS IS OK |
603 } |
603 } |
604 Object cache = securityCheckCache; // read volatile |
604 Object cache = securityCheckCache; // read volatile |
605 if (targetClass != null // instance member or constructor |
605 if (targetClass != null // instance member or constructor |
606 && Modifier.isProtected(modifiers) |
606 && Modifier.isProtected(modifiers) |
607 && targetClass != memberClass) { |
607 && targetClass != memberClass) { |
608 // Must match a 2-list of { caller, targetClass }. |
608 // Must match a 2-list of { caller, targetClass }. |
609 if (cache instanceof Class[]) { |
609 if (cache instanceof Class[]) { |
610 Class<?>[] cache2 = (Class<?>[]) cache; |
610 Class<?>[] cache2 = (Class<?>[]) cache; |
611 if (cache2[1] == targetClass && |
611 if (cache2[1] == targetClass && |
612 cache2[0] == caller) { |
612 cache2[0] == caller) { |
613 return; // ACCESS IS OK |
613 return true; // ACCESS IS OK |
614 } |
614 } |
615 // (Test cache[1] first since range check for [1] |
615 // (Test cache[1] first since range check for [1] |
616 // subsumes range check for [0].) |
616 // subsumes range check for [0].) |
617 } |
617 } |
618 } else if (cache == caller) { |
618 } else if (cache == caller) { |
619 // Non-protected case (or targetClass == memberClass or static member). |
619 // Non-protected case (or targetClass == memberClass or static member). |
620 return; // ACCESS IS OK |
620 return true; // ACCESS IS OK |
621 } |
621 } |
622 |
622 |
623 // If no return, fall through to the slow path. |
623 // If no return, fall through to the slow path. |
624 slowCheckMemberAccess(caller, memberClass, targetClass, modifiers); |
624 return slowVerifyAccess(caller, memberClass, targetClass, modifiers); |
625 } |
625 } |
626 |
626 |
627 // Keep all this slow stuff out of line: |
627 // Keep all this slow stuff out of line: |
628 void slowCheckMemberAccess(Class<?> caller, Class<?> memberClass, |
628 private boolean slowVerifyAccess(Class<?> caller, Class<?> memberClass, |
629 Class<?> targetClass, int modifiers) |
629 Class<?> targetClass, int modifiers) |
630 throws IllegalAccessException |
|
631 { |
630 { |
632 Reflection.ensureMemberAccess(caller, memberClass, targetClass, modifiers); |
631 if (!Reflection.verifyMemberAccess(caller, memberClass, targetClass, modifiers)) { |
|
632 // access denied |
|
633 return false; |
|
634 } |
|
635 |
|
636 // access okay |
|
637 logIfExportedByBackdoor(caller, memberClass); |
633 |
638 |
634 // Success: Update the cache. |
639 // Success: Update the cache. |
635 Object cache = (targetClass != null |
640 Object cache = (targetClass != null |
636 && Modifier.isProtected(modifiers) |
641 && Modifier.isProtected(modifiers) |
637 && targetClass != memberClass) |
642 && targetClass != memberClass) |
641 // Note: The two cache elements are not volatile, |
646 // Note: The two cache elements are not volatile, |
642 // but they are effectively final. The Java memory model |
647 // but they are effectively final. The Java memory model |
643 // guarantees that the initializing stores for the cache |
648 // guarantees that the initializing stores for the cache |
644 // elements will occur before the volatile write. |
649 // elements will occur before the volatile write. |
645 securityCheckCache = cache; // write volatile |
650 securityCheckCache = cache; // write volatile |
|
651 return true; |
|
652 } |
|
653 |
|
654 // true to print a stack trace when access fails |
|
655 private static volatile boolean printStackWhenAccessFails; |
|
656 |
|
657 // true if printStack* values are initialized |
|
658 private static volatile boolean printStackPropertiesSet; |
|
659 |
|
660 /** |
|
661 * Returns true if a stack trace should be printed when access fails. |
|
662 */ |
|
663 private static boolean printStackTraceWhenAccessFails() { |
|
664 if (!printStackPropertiesSet && VM.initLevel() >= 1) { |
|
665 String s = GetPropertyAction.privilegedGetProperty( |
|
666 "sun.reflect.debugModuleAccessChecks"); |
|
667 if (s != null) { |
|
668 printStackWhenAccessFails = !s.equalsIgnoreCase("false"); |
|
669 } |
|
670 printStackPropertiesSet = true; |
|
671 } |
|
672 return printStackWhenAccessFails; |
646 } |
673 } |
647 } |
674 } |