跳到主要内容

JEP 176:调用者敏感方法的机械检查

QWen Max 中英对照

概述

通过用一种能够准确识别调用敏感方法并可靠地发现其调用者的机制,来取代现有的手工维护的调用敏感方法列表,从而提高 JDK 方法句柄实现的安全性。

非目标

提议的 @CallerSensitive 注解可能对其他类型的分析或审计有用,但此类活动超出了本 JEP 的范围。

同时,提供非系统代码的公共 API 也不是我们的目标。

描述

调用者敏感方法 会根据其直接调用者的类来改变行为。它通过调用 sun.reflect.Reflection.getCallerClass 方法来发现调用者的类。

大多数对调用者敏感的方法在某种程度上充当了调用者的代理。当通过反射调用这些方法时,必须特别处理它们,以确保 getCallerClass 方法返回的是实际调用者的类,而不是反射机制本身的某个类。实现这一逻辑需要针对一个手工维护的调用者敏感方法列表进行模式匹配,这种方法既脆弱又难以维护。

为了对此进行改进,我们将使用内部注解 @sun.reflect.CallerSensitive 标记 JDK 中所有与调用者相关的方法。JVM 将跟踪此注解,并且可选择强制执行一个不变量:即 sun.reflect.Reflection.getCallerClass 方法只能在某个方法被标记为此注解时报告该方法的调用者。JVM 在解析 MemberName 时会设置一个新的与调用者相关的标志位,同时包私有的方法 java.lang.invoke.MethodHandleNatives.isCallerSensitive 将被升级为直接查询该标志位,而不是查阅方法名称列表。

@CallerSensitive 注解可能对其他用途很有用,比如跟踪新的调用者敏感方法的引入,或者在 sun.reflect.misc.MethodUtil.invoke 方法中提供类似的特殊处理。

在 JDK 中有两个地方的方法会检查超出其直接调用者之外的堆栈帧。为了可靠地执行调用者敏感性检查,我们提议进行以下更改:

  • 弃用 SecurityManager.checkMemberAccess 方法,计划在未来版本中将其更改为无条件抛出异常。checkMemberAccess 方法要求调用者的帧在栈深度为四的位置,这种设计较为脆弱且难以强制执行。
  • 修订 java.util.logging.Logger,使其不再通过遍历栈来查找资源包。此栈遍历原本是作为一种临时措施,用于允许容器过渡到使用上下文类加载器。该方法已经被指定将在未来版本中移除。

替代方案

添加上述的 @CallerSensitive 注解,但仅用于验证手动维护的方法列表。这种方法是一种改进,但在运行时检查注解会更加可靠。

测试

现有的测试套件将很好地作为该功能的正面测试用例。需要新的负面测试用例来识别未正确标记的调用者敏感方法。

风险与假设

这一变化存在导致副作用的小风险。我们假设,对 JDK 8 已计划的大量测试将揭示任何此类问题。

影响

  • 性能:我们预计性能影响可以忽略不计。JVM 已经在为 JSR 292 解析运行时方法注解,与昂贵的栈遍历操作相比,该检查的开销相对较小。
  • 兼容性:依赖于 Logger 类的栈遍历行为的应用程序将不再正常工作。