Skip to content

JEP 176: Mechanical Checking of Caller-Sensitive Methods | 调用敏感方法的机械检查

摘要

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

非目标

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

此外,也不打算为非系统代码提供公共 API。

描述

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

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

为了改进这一点,我们将在 JDK 中将所有调用者敏感方法标记为内部注解 @sun.reflect.CallerSensitive。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 类堆栈遍历行为的应用程序将不再工作。