ShadowCallStack

ShadowCallStack (SCS) 是一种 LLVM instrumentation 模式,可通过将函数的返回地址保存到单独分配的 ShadowCallStack 中(在非叶函数的函数序言中),并在函数尾声中从 ShadowCallStack 加载返回地址,从而防止返回地址被覆盖(例如堆栈缓冲区溢出)。返回地址也存储在常规堆栈上,以便与展开程序兼容,但在其他情况下不使用。这可确保修改常规堆栈上的返回地址的攻击对程序控制流没有影响。

在 aarch64 上,instrumentation 利用 x18 寄存器来引用 ShadowCallStack,这意味着对 ShadowCallStack 的引用不必存储在内存中。这使得可以实现一种运行时,避免向可以读取任意内存的攻击者暴露 ShadowCallStack 的地址。

实现

Android 内核和用户空间均支持 ShadowCallStack。

为内核启用 SCS

要为内核启用 ShadowCallStack,请将以下行添加到内核配置文件

CONFIG_SHADOW_CALL_STACK=y

在用户空间中启用 SCS

要在用户空间组件中启用 ShadowCallStack,请将以下行添加到组件的 blueprint 文件

sanitize: {
  scs: true
}

SCS 假定 x18 寄存器保留用于存储 ShadowCallStack 的地址,并且不用于任何其他目的。虽然所有系统库都经过编译以保留 x18 寄存器,但如果为与进程内旧代码互操作的用户空间组件启用 SCS(例如,第三方应用可以加载的库),这可能会带来问题,因为这些旧代码可能会破坏 x18 寄存器。因此,我们仅建议在不会加载到旧二进制文件中的独立组件中启用 SCS。

验证

没有专门针对 SCS 的 CTS 测试。相反,请确保在启用和未启用 SCS 的情况下 CTS 测试均能通过,以验证 SCS 是否不会影响设备。