> For the complete documentation index, see [llms.txt](https://lightc.gitbook.io/pwn-gitbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lightc.gitbook.io/pwn-gitbook/kpwn/kpwn-tricks/nei-he-dui-uaf.md).

# 内核堆UAF

内核的堆内存主要来源于线性映射区，主要使用 `kmalloc` 分配函数和 `slub` 分配区。

## CPU 核心绑定

`slub` 分配区会优先从当前核心的 `kmem_cache_cpu` 中进行内存分配，多个核心存在多个 `kmem_cache_cpu`，进程的调度可能让我们的程序不同时间在不同核心下运行，导致我们的堆内存来源于不同的 `kmem_cache_cpu`，利用变得不必要的麻烦。

可以将我们的进程绑定到特定的某个 CPU 核心上：

```c
#define _GNU_SOURCE
#include <sched.h>

/* to run the exp on the specific core only */
void bind_cpu(int core)
{
    cpu_set_t cpu_set;

    CPU_ZERO(&cpu_set);
    CPU_SET(core, &cpu_set);
    sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);
}
```

## GFP\_KERNEL 与 GFP\_KERNEL\_ACCOUNT

内核最为常见和通用的 `flag` 为 `GFP_KERNEL` 和 `GFP_KERNEL_ACCOUNT`，通常来自同一个 `kmem_cache`。

* `GFP_KERNEL_ACCOUNT`：表示该对象与来自用户空间的数据相关联
* `GFP_KERNEL`：则相反

自 5.14 开始，这两种 `flag` 的分配被隔离，`GFP_KERNEL_ACCOUNT` 有一组独立的 `kmem_cache` 称为 `kmalloc-cg-*`。
