推测控制

相当多的 CPU 具有与推测相关的缺陷,这些缺陷实际上是漏洞,导致各种形式的数据泄露,甚至跨越特权域。

内核以各种形式为这些漏洞提供缓解措施。 其中一些缓解措施是编译时可配置的,有些可以通过内核命令行提供。

还有一类缓解措施非常昂贵,但它们可以限制在受控环境中的特定进程或任务集。 控制这些缓解措施的机制是通过prctl(2)

有两个与此相关的 prctl 选项

  • PR_GET_SPECULATION_CTRL

  • PR_SET_SPECULATION_CTRL

PR_GET_SPECULATION_CTRL

PR_GET_SPECULATION_CTRL 返回使用 prctl(2) 的 arg2 选择的推测缺陷的状态。 返回值使用位 0-3,其含义如下

定义

描述

0

PR_SPEC_PRCTL

可以通过 PR_SET_SPECULATION_CTRL 按任务控制缓解措施。

1

PR_SPEC_ENABLE

推测功能已启用,缓解措施已禁用。

2

PR_SPEC_DISABLE

推测功能已禁用,缓解措施已启用。

3

PR_SPEC_FORCE_DISABLE

与 PR_SPEC_DISABLE 相同,但无法撤消。 后续的 prctl(..., PR_SPEC_ENABLE) 将失败。

4

PR_SPEC_DISABLE_NOEXEC

与 PR_SPEC_DISABLE 相同,但在 execve(2) 上将清除状态。

如果所有位均为 0,则 CPU 不受推测缺陷的影响。

如果设置了 PR_SPEC_PRCTL,则可以使用每任务控制缓解措施。 如果未设置,则对推测缺陷的 prctl(PR_SET_SPECULATION_CTRL) 将失败。

PR_SET_SPECULATION_CTRL

PR_SET_SPECULATION_CTRL 允许控制推测缺陷,该缺陷由 prctl(2) 的 arg2 按任务选择。 arg3 用于传入控制值,即 PR_SPEC_ENABLE 或 PR_SPEC_DISABLE 或 PR_SPEC_FORCE_DISABLE。

常见错误代码

含义

EINVAL

该架构未实现 prctl,或者未使用的 prctl(2) 参数不为 0。

ENODEV

arg2 选择了一个不受支持的推测缺陷。

PR_SET_SPECULATION_CTRL 错误代码

含义

0

成功

ERANGE

arg3 不正确,即它既不是 PR_SPEC_ENABLE,也不是 PR_SPEC_DISABLE,也不是 PR_SPEC_FORCE_DISABLE。

ENXIO

无法控制所选的推测缺陷。 请参阅 PR_GET_SPECULATION_CTRL。

EPERM

推测已通过 PR_SPEC_FORCE_DISABLE 禁用,并且调用者试图再次启用它。

推测缺陷控制

  • PR_SPEC_STORE_BYPASS:推测性存储旁路

    调用
    • prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, 0, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE_NOEXEC, 0, 0);

  • PR_SPEC_INDIR_BRANCH:用户进程中的间接分支推测

    (缓解针对用户进程的 Spectre V2 样式攻击)

    调用
    • prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, 0, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_ENABLE, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_DISABLE, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_INDIRECT_BRANCH, PR_SPEC_FORCE_DISABLE, 0, 0);

  • PR_SPEC_L1D_FLUSH:在任务切换出上下文时刷新 L1D 缓存

    (仅当任务在非 SMT 核心上运行时有效)

    调用
    • prctl(PR_GET_SPECULATION_CTRL, PR_SPEC_L1D_FLUSH, 0, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_L1D_FLUSH, PR_SPEC_ENABLE, 0, 0);

    • prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_L1D_FLUSH, PR_SPEC_DISABLE, 0, 0);