> 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/man9/kasan.9.md).

# kasan(9)

`KASAN` — 内核地址消毒器

## 名称

`KASAN`

## 概要

GENERIC-KASAN 内核配置可用于以 GENERIC 为基础配置编译启用 KASAN 的内核。或者，要将 KASAN 编译进内核，请将以下行放入你的内核配置文件中：

> options KASAN

```c
#include <sys/asan.h>

void
kasan_mark(const void *addr, size_t size, size_t redzsize, uint8_t code)
```

## 描述

`KASAN` 是一个利用编译器插桩检测内核中无效内存访问的子系统。目前在 amd64 和 arm64 平台上实现。

当 `KASAN` 编译进内核时，编译器被配置为在每次内存访问时发出函数调用。这些函数由 `KASAN` 实现，允许运行时检测若干类型的错误，包括释放后使用、双重释放和释放无效指针，以及越界访问。这些保护适用于由 uma(9)、[malloc(9)](/man9/malloc.9.md) 及相关函数，以及 `kmem_malloc` 和相关函数分配的内存，还有全局变量和内核栈。`KASAN` 是保守的，不会检测所有此类错误的实例。通过内核映射的内存访问会被消毒，但通过直接映射的访问不会。当配置 `KASAN` 时，内核旨在尽量减少对直接映射的使用。

## 实现说明

`KASAN` 使用编译器插桩和内核运行时实现。当构建启用 KASAN 选项的内核时，编译器在生成代码中的大多数内存访问之前插入函数调用。运行时实现相应的函数，决定给定访问是否有效。如果无效，运行时根据 `debug.kasan.panic_on_violation` sysctl/可调参数的值打印警告或使内核崩溃。

KASAN 配置的内核中的 `KASAN` 运行时可通过设置 loader 可调参数 `debug.kasan.disable=1` 禁用。

`KASAN` 运行时通过为内核映射维护影子映射来工作。内核映射中的地址与影子映射中的地址之间存在线性映射关系。影子映射用于存储有关内核映射分配的当前状态信息。例如，当 [malloc(9)](/man9/malloc.9.md) 返回缓冲区时，影子映射的相应区域被标记为指示缓冲区有效。当其被释放时，影子映射更新为将缓冲区标记为无效。对缓冲区的访问由 `KASAN` 运行时拦截，并使用影子映射的内容进行验证。

启动时，所有内核内存被标记为有效。内核分配器必须将缓存但空闲的缓冲区标记为无效，并在释放内核虚拟地址范围之前将其标记为有效。这略微降低了 `KASAN` 的有效性，但简化了其维护和与内核的集成。

通过调用 `kasan_mark` 执行影子映射的更新。参数 `addr` 是要更新影子的缓冲区地址，`size` 是缓冲区的可用大小，`redzsize` 是从系统底层分配的缓冲区的完整大小。`redzsize` 必须大于或等于 `size`。在某些情况下，内核分配器会返回大于消费者请求的缓冲区；末尾未使用的空间称为红区，始终标记为无效。`code` 允许调用者在将缓冲区标记为无效时指定一个标识符。该标识符包含在 `KASAN` 生成的任何报告中，有助于识别无效访问的来源。例如，当项被释放到 uma(9) 区时，该项用 `KASAN_UMA_FREED` 标记。可用标识符参见以下文件：

```c
#include <sys/asan.h>
```

如果整个缓冲区要标记为有效，即 `size` 和 `redzsize` 相等，`code` 应为 0。

## 参见

[build(7)](/man7/build.7.md), KMSAN(9), [malloc(9)](/man9/malloc.9.md), [memguard(9)](/man9/memguard.9.md), [redzone(9)](/man9/redzone.9.md), uma(9)

## 历史

`KASAN` 从 NetBSD 移植，首次出现于 FreeBSD 13.1。

## 缺陷

`KASAN` 运行时忽略对内核映射之外的内核内存的访问。当配置 `KASAN` 时，内核内存分配器被配置为使用内核映射，但仍存在一些对直接映射的使用。例如，在 amd64 和 arm64 上，对页表页的访问不被跟踪。

某些内核内存分配器明确允许在对象被释放后访问。这些无法由 `KASAN` 消毒。例如，从所有使用 `UMA_ZONE_NOFREE` 标志初始化的 uma(9) 区的内存不被消毒。
