跳到主要内容

JEP 176: Mechanical Checking of Caller-Sensitive Methods

Summary

Improve the security of the JDK's method-handle implementation by replacing the existing hand-maintained list of caller-sensitive methods with a mechanism that accurately identifies such methods and allows their callers to be discovered reliably.

Non-Goals

The proposed @CallerSensitive annotation may be useful for other types of analyses or audits, but such activities are beyond the scope of this JEP.

It is also not a goal to provide a public API for non-system code.

Description

A caller-sensitive method varies its behavior according to the class of its immediate caller. It discovers its caller's class by invoking the sun.reflect.Reflection.getCallerClass method.

Most caller-sensitive methods act in some way as an agent for the caller. When invoked via reflection, these methods must be handled specially in order to ensure that the class of the actual caller, rather than some class of the reflection mechanism itself, is returned by the getCallerClass method. The logic for doing this involves pattern matching against a hand-maintained list of caller-sensitive methods, which is brittle and difficult to maintain.

To improve on this we will mark all caller-sensitive methods in the JDK with the internal annotation @sun.reflect.CallerSensitive. The JVM will track this annotation and, optionally, enforce the invariant that the sun.reflect.Reflection.getCallerClass method can only report the caller of a method when that method is marked with this annotation. The JVM will set a new caller-sensitive bit when resolving a MemberName, and the package-private method java.lang.invoke.MethodHandleNatives.isCallerSensitive will be upgraded to query it directly rather than consult a list of method names.

The @CallerSensitive annotation might be useful for other purposes, such as tracking the introduction of new caller-sensitive methods or providing similar special handling in the sun.reflect.misc.MethodUtil.invoke method.

There are two places in the JDK where methods examine stack frames beyond their immediate callers. We propose the following changes in order to enforce the caller-sensitivity check reliably:

  • Deprecate the SecurityManager.checkMemberAccess method, with a view to changing it to throw an exception unconditionally in a future release. The checkMemberAccess method requires the caller's frame to be at a stack depth of four, which is fragile and difficult to enforce.

  • Revise java.util.logging.Logger not to walk the stack in search of a resource bundle. This stack walk was intended as a temporary measure to allow containers to transition to using the context class loader. It is already specified to be removed in a future release.

Alternatives

Add the @CallerSensitive annotation, as described above, but use it only to validate the hand-maintained method list. This alternative would be an improvement, but checking the annotation at runtime is more reliable.

Testing

Existing test suites will serve well as positive test cases for this feature. New negative test cases are required to identify caller-sensitive methods that are not properly marked.

Risks and Assumptions

There is a small risk that this change will cause side effects. We assume that the already-planned extensive testing of JDK 8 will uncover any such issues.

Impact

  • Performance: We expect negligible performance impact. The JVM is already parsing runtime method annotations for JSR 292 and the check will be relatively cheap compared to the expensive stack-walk operation.

  • Compatibility: Applications that depend upon the stack-walking behavior of the Logger class will no longer work.