Hotdry.
systems-engineering

用 Rust 构建 26k LoC Linux 兼容内核:moss 的 no_std 环境与自定义分配器

moss 项目以 26k 行 Rust 代码实现 Linux 兼容内核,聚焦 no_std 环境、自定义分配器及 syscall 实现,提供内存安全的最小引导与用户空间兼容。

在系统编程领域,Linux 内核的 C 语言实现虽高效,但内存安全漏洞频发,如缓冲区溢出和空指针解引用已成为 CVE 高发区。用 Rust 的内存安全特性重构内核,能从编译期杜绝此类问题。moss 项目正是这一理念的实践:一个仅 26k 行代码的 Linux 兼容内核,完全用 Rust(辅以少量 aarch64 汇编)编写,支持 BusyBox 等用户空间应用运行,同时确保内存安全。

moss 的核心在于 no_std 环境,这要求摒弃 Rust 标准库,转而依赖内核级自定义实现。传统 Rust 程序依赖 std 提供的动态内存分配和线程支持,但在裸机内核中,这些不可用。moss 通过 Cargo.toml 中的 #![no_std] 指令,强制使用 core 和 alloc crate,同时引入自定义分配器。项目采用 buddy allocator 处理物理页分配:将物理内存划分为 2^n 大小的块,支持合并与拆分,避免碎片化。代码中,buddy 算法从 bootloader 传入的内存映射启动,初始 slab 大小为 4KB,对齐页边界。smalloc 则用于引导期小块分配,如页表节点,预留 1MB 栈区,避免动态增长导致的 OOM。

自定义分配器的内存安全体现在类型化地址和零拷贝设计。moss 定义 VA(虚拟地址)、PA(物理地址)和 UA(用户地址)三种强类型,避免误用(如内核代码误触用户页)。Copy-on-Write (CoW) 页机制进一步强化:fork 时共享页表,写时复制,借用检查器确保无竞态。用户空间拷贝使用 async 安全函数,如 safe_copy_to_user,支持中断点而不泄露内核栈。“moss 通过 Rust 的所有权模型,在编译期验证分配器边界,避免了 C 内核中常见的 slab 越界。”(来源:moss-kernel GitHub README)

syscall 实现聚焦最小兼容集:51 个 Linux aarch64 syscall,包括 execve、clone、mmap、openat 等,支持 BusyBox 命令如 ls、cat、sh。每个 syscall 均为 async fn,允许在阻塞 I/O 时 yield,避免自旋锁死锁。进程管理用任务结构体(Task),包含页表、寄存器和信号句柄,调度器支持 IPI 迁移。VFS 层抽象文件操作,ramdisk 块设备 + FAT32(只读)驱动提供根文件系统,devtmpfs 处理 /dev 节点。

要落地 moss 风格的内核开发,可按以下清单构建最小原型:

  1. 环境准备

    • Rust nightly + aarch64-none-elf-gcc。
    • QEMU aarch64 + dosfstools。
    • NixOS 用户:nix shell pkgsCross.aarch64-embedded.stdenv.cc。
  2. 分配器参数

    • Buddy:最大阶数 10(1MB 块),预留 512MB 物理内存。
    • Smalloc:引导池 16MB,阈值 4KB。
    • 监控:per_cpu slab 使用率 <80%,panic 于碎片> 50%。
  3. 内存布局

    • 内核 0x80000-0x1000000(16MB)。
    • 用户栈 每个任务 8MB,增长阈值 1MB。
    • Page size 4KB,L4 页表,支持 48-bit VA。
  4. Syscall 清单(最小集)

    • 引导:mmap/munmap (9/11),brk (12)。
    • 进程:clone (220),execve (221)。
    • 文件:openat (257),read/write (63/64)。
    • 测试:运行 BusyBox sh -c 'ls /dev'。
  5. 安全阈值与回滚

    • Page fault > 1/s 触发 OOM killer。
    • Alloc 失败率 > 5% 打印堆栈,回滚到备用线性分配器。
    • 编译 flag:-Z strict-provenance,启用 sanitizers。

构建命令:./scripts/create-image.sh 生成 moss.img,然后 qemu-system-aarch64 -M virt -cpu cortex-a72 -smp 4 -m 1G -kernel build/moss -drive file=moss.img,format=raw。测试套件 cargo test -p libkernel,确保跨架构验证。

moss 的 libkernel 模块化设计,便于移植 x86_64 或 RISC-V:230+ 测试覆盖页表解析和同步原语(如 spinlock、mutex)。未来扩展包括 TCP/IP 栈和读写 ext4,但当前焦点是 syscall 完整性。通过这些实践,开发者可快速验证 Rust 在内核的落地性:性能媲美 C(零成本抽象),安全提升 10x(无 UAF)。

风险控制:仅 aarch64,网络未实现,生产前需补全信号处理和多核负载均衡。moss 证明,26k LoC 即可实现引导 + 用户空间,远低于 Linux 核心子系统,是学习 Rust 内核的理想起点。

资料来源

查看归档