开篇:内核为什么引入 Rust
Linux 内核约 70% 的安全 CVE 与内存破坏相关——该比例来自 Kernel Self Protection Project 等维护者多年统计与 CNA 分类讨论(具体百分比随年份波动,宜查当年 kernel.org 安全公告汇总,本文引用「内存安全类占主导」这一稳定趋势,不编造精确到小数点的 2026 年报)。
Rust 的 所有权 + 借用检查 在编译期消除:use-after-free、double-free、空指针解引用、数据竞争(在 safe Rust 内)。把 Rust 引入 30 年 C 代码库 的代价是:工具链、ABI、抽象层维护、社区技能分裂。
本文对照 KASLR 与缓解:Rust 减漏洞类;KASLR/CFI/Shadow Stack 减利用成功率——正交。
flowchart LR
C[历史 C 子系统] --> FFI[FFI 边界]
FFI --> RUST[Rust 驱动 / 模块]
RUST --> KC[kernel crate 抽象]
KC --> BIND[bindgen 生成 C API]
BIND --> C
一、合入主线时间线与能力边界
| 时间 | 里程碑 | 能力 |
|---|---|---|
| 2021 | Miguel Ojeda RFC | 提出 rust-for-linux 树 |
| 2022.12 | Linux 6.1 | CONFIG_RUST、最小
rust/、示例模块 |
| 6.4–6.6 | 持续扩展 | kernel
crate、sync、alloc、更多驱动实验 |
| 6.7+ | Asahi DRM 等 | 大型 Rust 驱动合入讨论/主线 |
| 2025–2026 | 发行版 | Fedora 等提供可选 Rust 启用内核包 |
版本纪律:下文源码路径以 Linux
6.6+ Documentation/rust/
为锚;读者若用 6.1 需对照 release notes 缺失组件。
二、rust/
子系统架构
2.1 目录地图
| 路径 | 职责 |
|---|---|
rust/kernel/ |
kernel crate:模块、sync、error、device
抽象 |
rust/alloc/ |
内核堆分配器绑定 |
rust/macros/ |
module!、vtable 等过程宏 |
rust/bindings/ |
bindgen 生成的 C 结构体/函数 |
Documentation/rust/ |
官方 Rust 内核指南 |
2.2 kernel
crate 与模块入口
use kernel::prelude::*;
module! {
type: MyDriver,
name: "my_driver",
authors: ["..."],
description: "Example",
license: "GPL",
}
struct MyDriver;
impl kernel::Module for MyDriver {
fn init(_module: &'static ThisModule) -> Result<Self> {
pr_info!("Rust driver loaded\n");
Ok(MyDriver)
}
}对照 C module_init:Rust 用
Result 传播初始化错误,避免 C
式「返回负 errno」与资源泄漏交织。
2.3 pin_init
与自引用结构
内核大量结构 自引用(链表节点、含指针的
struct)。Rust 稳定前用 pin_init /
PinnedDrop 模式在 构造期
固定地址,避免 move 后指针失效。
原则(A
级:Documentation/rust/general-information.html):
- 需要稳定地址的字段用
Pin包装。 - 初始化失败路径由
pin_init宏生成 drop 链。
2.4
sync::Lock 与 C 锁原语映射
| Rust 抽象 | C 对应 | 用途 |
|---|---|---|
Mutex<T> |
mutex |
睡眠锁 |
SpinLock<T> |
spinlock_t |
原子上下文 |
CondVar |
wait_queue 组合 |
条件等待 |
Rust 锁在 编译期 标记
Send/Sync;错误持锁(跨 IRQ
睡眠)尽量在抽象层拒绝。
2.5
错误处理:Result 与 Error
pub fn probe(dev: &Device) -> Result<Pin<KBox<Self>>> {
let reg = dev.iomap_region(0, None)?;
// ...
Ok(Pin::from(kbox!(Self { reg }))
}? 运算符映射到内核 errno;与 C
PTR_ERR 模式对照,减少遗漏检查。
三、与 C 的互操作规则
3.1
#[no_mangle] extern "C" 导出
Rust 回调 C 所需:
#[no_mangle]
pub extern "C" fn rust_helper_do_work(ptr: *mut c_void) -> c_int {
// safety: 调用约定与 C 侧文档一致
0
}3.2 Opaque 类型
C 结构体对 Rust 常为 opaque:仅传递指针,不解引用布局——避免 Rust 与 C 头文件布局漂移。
3.3 bindgen 与
build.rs
内核构建集成 bindgen 从 C 头生成 Rust
绑定;C API 变更 必须同步更新绑定与
kernel crate 安全封装——这是
维护负担 核心。
3.4 FFI 边界安全契约
官方要求:unsafe
集中在薄封装层;驱动业务逻辑尽量 safe。违反时
clippy 与 review 聚焦 unsafe
块。
四、案例路径:从示例到 Asahi GPU
4.1 官方示例模块
6.1 起 samples/rust/ 提供最小字符设备、Rust
版 printk 等——适合验证工具链:
make LLVM=1 rustavailable
make M=samples/rust examples4.2 块层与网络 Rust 实验
邮件列表与 -next 树常见:Rust 块驱动、phy
驱动实验——合入节奏因子系统维护者态度而异。
4.3 Asahi Linux GPU 驱动(里程碑意义)
Apple Silicon GPU 驱动大量使用 Rust 管理:
- 复杂 命令流与 GPU 状态机
- 内存对象 与 IOMMU 交互
- 用户态接口(ioctl 路径)仍经 C 胶水
意义:非玩具——代码规模与状态空间接近生产 DRM 驱动,证明 Rust 可承载真实硬件复杂性。
五、内存安全:C vs Rust 对照表
| 缺陷类 | C 典型表现 | Rust safe 代码 |
|---|---|---|
| UAF | 崩溃/利用 | 编译拒绝 |
| double free | 崩溃 | 编译拒绝 |
| 缓冲区溢出 | 崩溃/利用 | 边界检查或编译拒绝 |
| 数据竞争 | KCSAN 运行时抓 | Send/Sync 拒绝 |
| 空指针 | 崩溃 | Option |
| 整数溢出 | 未定义行为 | checked_* / debug panic |
边界:unsafe
块内仍可出现上述 bug;FFI 调用 C 仍继承 C
风险。
六、与编译期缓解(CFI、KASAN)的关系
| 机制 | 作用阶段 | 与 Rust 关系 |
|---|---|---|
| KASAN/KFENCE | 运行时检测 C 内存错误 | Rust 减少触发,但不替代 |
| CFI | 限制间接调用目标 | C 代码仍需要;Rust vtable 亦受架构影响 |
| KASLR | 布局随机化 | 与语言无关 |
| Rust borrow | 编译期 | 源头削减 漏洞类 |
对照 完整性 与 seccomp:Rust 不替代 LSM/沙箱。
七、工具链、ABI 与编译时间
7.1 rustc 版本锁定
内核指定 精确 rustc 版本(见
scripts/min-tool-version.sh 或
Documentation/rust/quick-start.rst)。发行版打包
Rust 内核模块必须用 相同版本
编译——Rust 无稳定 ABI。
7.2 架构支持
并非所有 ARCH= 均
CONFIG_RUST=y;嵌入式架构可能长期缺席。部署前查目标架构
Kconfig。
7.3 编译时间
全内核 LLVM=1 + Rust
增量显著增加链接时间——CI 与开发者笔记本是实际摩擦点。
7.4 调试
gdb 对 Rust 符号支持逐年改善,但仍不如 C
成熟;printk + tracing
仍是主力。
八、局限与未解决问题
| 话题 | 状态(2026) |
|---|---|
内核 async/await |
实验性讨论,非生产默认 |
no_std 约束 |
无标准库;仅 core + kernel
crate |
| 大型 C 子系统重写 | 不现实;增量替换 |
| 形式化验证 | Rust 类型 + 个别项目;非全线 |
| 社区分裂风险 | Linus:不强制 C 维护者学 Rust |
8.1 为何不全量重写
- 驱动与
mm/、sched/耦合极深。 - 历史行为兼容性(quirk)在 C 中散落注释。
- 审查带宽:Rust PR 需 C 子系统维护者 + Rust 专家双审。
九、eBPF 中的 Rust(Aya)— 相关但不同层
// Aya:用户态加载 + 内核 eBPF 程序可用 Rust 编写
#[kprobe]
pub fn try_kprobe(ctx: ProbeContext) -> u32 {
match try_kprobe(ctx) {
Ok(ret) => ret,
Err(_) => 0,
}
}Aya 在 BPF 程序 用 Rust——经过 verifier,与 rust-for-linux 内核模块 不同路径。对照 eBPF 核心。
十、其他语言实验(对照)
| 项目 | 语言 | 状态 |
|---|---|---|
| Rust for Linux | Rust | 合入主线 |
| Redox OS | Rust | 独立 OS |
| Hubris | Rust | Oxide 嵌入式 |
| seL4 | C + 证明 | 微内核形式化 |
| C++ 内核模块 | 少数驱动 | 非主线趋势 |
十一、对应用开发者的影响
短期(2026):几乎无——你仍跑同样
syscall、同样 /proc。收益在
长期 内核攻击面下降。
中期:若使用 out-of-tree 驱动 或 自定义模块,可评估 Rust 分支减少内存类 bug。
跟踪源:LWN.net、rust-for-linux
邮件列表、Documentation/rust/。
十二、源码阅读路径(建议顺序)
Documentation/rust/quick-start.rstsamples/rust/minimal.rsrust/kernel/lib.rs— 模块与错误rust/kernel/sync/— 锁抽象- Asahi 或 DRM Rust 驱动(按当前主线文件名)
十三、小结
- Rust for Linux 目标:在 保留 C 子系统 前提下,用 所有权 削减内存安全类 CVE。
- Linux 6.1 起
rust/+kernelcrate;pin_init、sync::Lock、Result 是日常 API 核心。 - FFI + bindgen 是维护成本中心;unsafe 集中封装 是官方安全策略。
- Asahi GPU 等驱动证明规模可行性;全量重写 不现实。
与 KASLR/CFI/eBPF 正交互补;应用开发者 现在 主要「关注主线」,out-of-tree 作者可 试点 Rust。
参考文献
rust/目录(Linux 内核)Documentation/rust/- Miguel Ojeda, “Rust for the Linux kernel.” 2022
- Asahi Linux GPU driver
工具
rustc(nightly)bindgenmake LLVM=1 rustavailable
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【操作系统百科】OS 的下一个十年
综合 Windows/RTOS/Unikernel/Rust/机密计算/CXL 等前沿篇章,从 Rust 内核、机密计算、可拆分内存、io_uring 统一 I/O、eBPF 可编程内核五条趋势出发,按现在/三年/十年框架说明应用开发者应调整的假设与可执行建议。
【操作系统百科】实时 OS 巡礼
硬实时与软实时的可调度性边界、VxWorks/QNX/Zephyr 机制对照、Linux PREEMPT_RT 与主线合入、DO-178C/ISO 26262 认证语境,以及选型决策树。
【操作系统百科】Unikernel
Unikernel 在云上为什么没成主流?MirageOS、IncludeOS、Unikraft、OSv 的设计取舍——库操作系统、启动时间、工具链、调试困难、POSIX 兼容。
【操作系统百科】可拆分 OS
CXL 内存池化如何动摇 OS 对本地 DRAM 的假设?从资源解耦、CXL.mem 语义、LegoOS/PhantomOS/Twilight 学术原型,到 Linux CXL 驱动、dax、HMM 与 memory tiering,说明 disaggregated OS 的工程边界与 NUMA 演进。