> For the complete documentation index, see [llms.txt](https://man.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://man.bsdcn.org/man7/mitigations.7.md).

# mitigations(7)

`mitigations` — FreeBSD 安全漏洞缓解措施

## 名称

`mitigations`

## 概要

`在 FreeBSD 中，采用了各种安全缓解措施来限制漏洞的影响，保护系统免受恶意攻击。其中一些缓解措施具有运行时控制，可在全局或每进程级别启用；一些在编译时可选地启用或禁用；还有一些是实现所固有的，没有控制选项。`

`本文档涵盖以下漏洞缓解措施：`

`地址空间布局随机化（ASLR）`

`位置无关可执行文件（PIE）`

`写异或执行（W^X）页面保护策略`

`PROT_MAX`

`重定位只读（RELRO）`

`立即绑定（Bind Now）`

`栈溢出保护`

`超级模式内存保护`

`Capsicum`

`固件和微码`

`体系结构漏洞缓解措施`

*
*
*
*
*
*
*
*
*
*
*

`请注意，这些缓解措施的有效性和可用性可能因 FreeBSD 版本和系统配置而异。`

## 描述

安全漏洞缓解措施是 FreeBSD 中采用的技术，用于限制软件和硬件中安全漏洞的潜在影响。必须理解，缓解措施并不直接解决潜在的安全问题。它们不能替代安全的编码实践。缓解措施作为额外的防御层，通过使攻击者更难实现其目标，帮助降低漏洞被成功利用的可能性。

本手册页描述了 FreeBSD 中实现的安全缓解措施，以增强操作系统的整体安全性。每种缓解措施都旨在防止特定类型的攻击和漏洞。

## 软件漏洞缓解措施

### 地址空间布局随机化（ASLR）

地址空间布局随机化（ASLR）是一种安全缓解技术，它通过随机化加载系统和应用程序代码、数据和库的内存地址来工作，使攻击者更难预测内存布局并利用漏洞。

ASLR 在进程执行期间将随机性引入内存布局，降低了内存地址的可预测性。ASLR 旨在使攻击者发现软件漏洞（如缓冲区溢出）时更难利用。

ASLR 可以在全局和每进程级别启用。全局控制由一组单独的 [sysctl(8)](/man8/sysctl.8.md) 旋钮提供，分别用于 32 位和 64 位进程。可以通过 proccontrol(1) 在每进程级别启用或禁用。注意，ASLR 模式更改在地址空间更改时（即 execve(2) 时）生效。

32 位进程的全局控制：

**`kern.elf32.aslr.enable`** 为 32 位 ELF 二进制文件启用 ASLR，位置无关可执行文件（PIE）二进制文件除外。

**`kern.elf32.aslr.pie_enable`** 为 32 位位置无关可执行文件（PIE）ELF 二进制文件启用 ASLR。

**`kern.elf32.aslr.honor_sbrk`** 保留传统的 sbrk(2) 区域，以与旧二进制文件兼容。

**`kern.elf32.aslr.stack`** 随机化 32 位 ELF 二进制文件的栈位置。

64 位进程的全局控制：

**`kern.elf64.aslr.enable`** 为 64 位 ELF 二进制文件启用 ASLR，位置无关可执行文件（PIE）二进制文件除外。

**`kern.elf64.aslr.pie_enable`** 为 64 位位置无关可执行文件（PIE）ELF 二进制文件启用 ASLR。

**`kern.elf64.aslr.honor_sbrk`** 保留传统的 sbrk(2) 区域，以与旧二进制文件兼容。

**`kern.elf64.aslr.stack`** 随机化 64 位 ELF 二进制文件的栈位置。

要在启用或禁用 ASLR 的情况下执行命令：

proccontrol `-m` `aslr` \[`-s` `enable | disable`] `command`

### 位置无关可执行文件（PIE）

PIE 二进制文件是没有固定加载地址的可执行文件。它们可以由 rtld(1) 运行时链接器加载到任意内存地址。配合 ASLR，它们在每次执行时都会加载到随机地址。

### 写异或执行（W^X）页面保护策略

写异或执行（W^X）是一种漏洞缓解策略，通过控制内存访问权限来加强系统安全性。

在 W^X 缓解下，内存页面可以是可写（W）的或可执行（E）的，但不能同时具备两者。这意味着在标记为可写的内存区域中阻止代码执行，而在标记为执行的区域中限制写入或修改内存。执行即时编译（JIT）的应用程序需要进行适配以与 W^X 兼容。

有单独的 [sysctl(8)](/man8/sysctl.8.md) 旋钮用于控制 32 位和 64 位进程的 W^X 策略执行。通过将适当的 `allow_wx` sysctl 设置为 0 来启用 W^X 策略。

**`kern.elf32.allow_wx`** 允许 32 位进程同时映射可写和可执行的页面。

**`kern.elf64.allow_wx`** 允许 64 位进程同时映射可写和可执行的页面。

### PROT\_MAX

`PROT_MAX` 是 FreeBSD 对 mmap(2) 的特定扩展。`PROT_MAX` 提供了设置由 mmap(2) 分配并随后由 mprotect(2) 修改的区域的最大保护的能力。例如，最初以 mmap prot 参数 PROT\_MAX(PROT\_READ | PROT\_WRITE) | PROT\_READ 分配的内存可以通过未来的 mprotect(2) 调用变为可写，但不能变为可执行。

### 重定位只读（RELRO）

重定位只读（RELRO）是一种缓解工具，在 rtld(1) 进行重定位处理后，将程序地址空间中包含 ELF 元数据的某些部分设为只读。

单独启用时，RELRO 选项提供 *部分 RELRO* 支持。在这种情况下，全局偏移表（GOT）中与过程链接表（PLT）相关的部分（通常位于名为 .got.plt 的节中）保持可写。

RELRO 默认启用。可以使用 [src.conf(5)](/man5/src.conf.5.md) 构建时选项 `WITHOUT_RELRO` 禁用它。

### BIND\_NOW

`WITH_BIND_NOW` [src.conf(5)](/man5/src.conf.5.md) 构建时选项使二进制文件在构建时设置 `DF_BIND_NOW` 标志。运行时加载器 rtld(1) 将在进程启动时执行所有重定位处理，而不是按需（在首次访问每个符号时）执行。

与 `RELRO`（默认启用）结合启用时，这提供了 *完整 RELRO*。整个 GOT（.got 和 .got.plt）在程序启动时变为只读，防止对重定位表的攻击。注意，这会导致非标准的应用程序二进制接口（ABI），某些应用程序可能无法正常工作。

### 栈溢出保护

FreeBSD 支持使用栈溢出保护（SSP）编译器特性进行栈溢出保护。如果编译器支持给定体系结构，还会启用栈冲突保护。在用户空间中，SSP 在每个栈帧的末尾添加一个每进程随机化的金丝雀值，在函数返回时检查其是否被破坏，并以 `PAGE_SIZE` 为块进行栈探测。在内核中，全局使用一个随机化的金丝雀值，aarch64 除外，它有一个 `PERTHREAD_SSP` [config(8)](/man8/config.8.md) 选项来启用每线程随机化金丝雀。如果检测到栈破坏，则进程中止，以避免因破坏而可能导致的恶意执行。可以使用 [src.conf(5)](/man5/src.conf.5.md) SSP 旋钮在构建 FreeBSD 基本系统时启用或禁用 SSP。

当启用 `WITH_SSP` 时（这是默认设置），world 使用 `-fstack-protector-strong` 和 `-fstack-clash-protection` 编译器选项构建。内核使用 `-fstack-protector` 选项构建。

除 SSP 外，还支持最高级别 2 的“FORTIFY\_SOURCE”实现，方法是在包含任何 FreeBSD 头文件之前将 `_FORTIFY_SOURCE` 定义为 `1` 或 `2`。FreeBSD world 构建可以在环境或 **/etc/src-env.conf** 中设置 `FORTIFY_SOURCE`，以提供 `_FORTIFY_SOURCE` 的默认值。启用时，“FORTIFY\_SOURCE”在接受要写入缓冲区的各种函数中启用额外的边界检查。这些函数目前支持额外的边界检查：

| Fn bcopy    | Fn bzero   | Fn fgets   | Fn getcwd    | Fn gets     |
| ----------- | ---------- | ---------- | ------------ | ----------- |
| Fn memcpy   | Fn memmove | Fn memset  | Fn read      | Fn readlink |
| Fn snprintf | Fn sprintf | Fn stpcpy  | Fn stpncpy   | Fn strcat   |
| Fn strcpy   | Fn strncat | Fn strncpy | Fn vsnprintf | Fn vsprintf |

“FORTIFY\_SOURCE”需要 [clang(1)](/man1/clang.1.md) 或 gcc(1) 的编译器支持，它们提供 \_\_builtin\_object\_size(3) 函数，用于确定对象的边界。此功能在 `-O1` 及更高优化级别下效果最佳，因为如果没有编译器在优化过程中收集的某些数据，某些对象大小可能不太明显。

与 SSP 类似，违反对象边界将导致程序中止，以避免恶意执行。这有效地为某些类别的函数和系统调用提供了比 SSP 更细粒度的保护，以及为作为程序数据一部分分配的缓冲区提供了一些保护。

### 超级模式内存保护

某些处理器包含这样的功能：在特权模式下，防止对用户空间（非特权）代码可访问的内存页面的意外访问。一项功能防止执行，旨在缓解从用户空间利用内核漏洞。另一项功能防止从内核意外读取或写入用户空间内存。这也有效地防止了来自内核的 NULL 指针解引用。一种额外的机制——线性地址空间分离（LASS）——在某些 amd64 机器上可用。LASS 防止用户模式应用程序访问内核模式内存，也防止内核未经授权访问用户空间内存。与基于页表的权限控制不同，LASS 仅基于地址值。作为在硬件中实施此分离的后果，LASS 还提供了对某些推测执行侧信道攻击的缓解。

| **体系结构** | **功能** | **阻止的访问类型** |
| -------- | ------ | ----------- |
| amd64    | LASS   | 全部          |
| amd64    | SMAP   | 读/写         |
| amd64    | SMEP   | 执行          |
| arm64    | PAN    | 读/写         |
| arm64    | PXN    | 执行          |
| riscv    | SUM    | 读/写         |
| riscv    | -      | 执行          |

这些功能大多由内核自动使用，没有面向用户的配置。LASS 由 `hw.lass` 加载器可调参数控制。可用时默认启用。

### Capsicum

Capsicum 是一个轻量级的 OS 能力和沙箱框架。更多信息请参见 [capsicum(4)](/man4/capsicum.4.md)。

## 硬件漏洞缓解措施

### 固件和微码

近年来出现了源源不断的新硬件漏洞，特别是 CPU 漏洞，通常由推测执行的可检测微体系结构副作用引起，这些副作用会从其他线程或进程泄露私有数据，有时甚至泄露通常无法访问的内部 CPU 状态。硬件供应商通常在发现这些漏洞时通过发布微码更新来解决它们，然后这些更新可能被打包到平台固件更新中（历史上对于 PC 称为 BIOS 更新）或由操作系统在引导时更新的软件包中。

平台固件更新（如果制造商提供）是最好的防御，因为它们在早期引导期间提供覆盖。使用 FreeBSD Ports Collection 中的 `sysutils/flashrom` 安装它们。

如果平台固件更新不再可用，则可安装打包的微码，位于 `sysutils/cpu-microcode`，并可在运行时使用 loader.conf(5) 加载，详见软件包消息。

整体而言，对硬件漏洞的最佳防御是在可用时及时应用这些更新，越早越好（在引导过程中），并在可能时禁用受影响硬件的问题功能（如 CPU 同步多线程）。软件缓解措施仅是这些的部分替代品，但对于不受支持的硬件，或作为对供应商尚未解决的刚发现的漏洞的补充，它们可能很有用。某些软件缓解措施依赖于微码更新提供的硬件能力。

### 体系结构漏洞缓解措施

FreeBSD 通常的策略是默认应用所有不需要重新编译的操作系统级缓解措施，但运行它的特定硬件已知不受其影响的（有时需要固件更新）除外，或者那些对性能的损害与其提供的保护相比极不成比例的除外。操作系统级缓解措施通常会对特定工作负载产生明显的性能影响。如果你的威胁模型允许，可能需要尝试禁用其中一些以获得更好的性能。反过来，最小化风险可能需要你显式启用最昂贵的缓解措施。每个漏洞/缓解措施的描述都说明它是否默认启用以及在什么条件下启用。它还列出了用于强制特定状态的旋钮。

### Zenbleed

“Zenbleed”漏洞仅影响基于 Zen2 微体系结构的 AMD 处理器。与例如 Meltdown 和不同变种的 Spectre（通过留下微体系结构痕迹来泄露数据）不同，Zenbleed 是一个真正的硬件错误，影响 CPU 的体系结构状态。通过特定的指令序列（其最后几条被推测执行错误预测），有可能使先前由在同一物理核心上执行的某些前序或并发任务放入某个 XMM 寄存器的数据出现在某个 XMM 寄存器中（因此禁用同步多线程（SMT）并不是充分的保护）。

根据漏洞发现者的说法，所有基于 Zen2 的处理器都受到影响（参见 <https://lock.cmpxchg8b.com/zenbleed.html>）。截至 2023 年 8 月，AMD 未公开列出任何相关勘误，但已发布安全公告（AMD-SB-7008），标题为"跨进程信息泄露"，表示修复该漏洞的平台固件最早将于 2023 年底分发给制造商，Rome 处理器除外，对于 Rome 处理器已经可用。目前尚未宣布独立的 CPU 微码。发现者提到的唯一可直接应用的修复是设置一个未文档化 MSR 的某一位，据报道这能完全阻止 XMM 寄存器泄露。

FreeBSD 目前在所有 Zen2 处理器上默认设置此位。未来，可能仅对那些微码尚未更新到修复该漏洞的版本的 Zen2 处理器默认设置它，前提是此类微码更新已实际发布并经过社区测试。与此缓解措施相关联的旋钮如下：

**`machdep.mitigations.zenbleed.enable`** 一个读写的整数可调参数和 sysctl，指示是否应强制禁用（0）、启用（1）缓解措施，或留给 FreeBSD 选择性地应用（2）。任何其他整数值都会被静默转换并视为值 2。注意，在非 Zen2 处理器上运行时，此设置会被静默忽略，以便于将通用配置应用于异构机器。

**`machdep.mitigations.zenbleed.state`** 一个只读字符串，指示当前缓解状态。它可以是"不适用"（如果处理器不是基于 Zen2 的）、"缓解已启用"或"缓解已禁用"。每次写入 sysctl `machdep.mitigations.zenbleed.enable` 时，此状态会自动更新。注意，如果通过 [cpuctl(4)](/man4/cpuctl.4.md)（包括 cpucontrol(8) 实用程序）直接设置或清除 chicken bit，它可能变得不准确。

在配置和部署这些缓解措施时，应考虑与这些缓解措施相关的性能影响和威胁模型。

[security(7)](/man7/security.7.md) 的 Sx KNOBS AND TWEAKS 节中列出了其他缓解旋钮。

## 参见

elfctl(1), proccontrol(1), rtld(1), mmap(2), [src.conf(5)](/man5/src.conf.5.md), [sysctl.conf(5)](/man5/sysctl.conf.5.md), [security(7)](/man7/security.7.md), cpucontrol(8), [sysctl(8)](/man8/sysctl.8.md)
