如何使用rust写内核模块

本文涉及的产品
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 近年来,Rust语言以内存安全、高可靠性、零抽象等能力获得大量开发者关注,而这些特性恰好是内核编程中所需要的,所以我们看下如何用rust来写Linux内核模块。

Rust与内核模块

虽然Rust支持已经在Linux Kernel 6.1版本合并到主线了,所以理论上来说,开发者可以使用Rust来为Linux 6.1写内核模块。


但实际开发工作中,内核版本不是最新的,比如Debian 11的内核就是5.10版本的,那么在这种情况下,该如何用Rust写内核模块呢?


原理

  1. Rust如何向内核注册回调、如何调用内核代码。Rust和C的互操作性
  2. Rust如何编译到目标平台上。Rust的target配置
  3. Rust如何申明内核模块入口、并添加特殊section。Rust内核模块的二进制约定


Rust和C的互操作性

第一个问题基本上就是C和Rust的互操作性了。


得益于Rust的抽象层次,C语言和Rust的互相调用都是比较容易的。rust官方也提供了bindgen这样,根据.h文件生成.rs文件的库。


这样一来,貌似直接使用bindgen将内核头文件翻译成.rs就可以了?


但还有一个问题,如何获取内核头文件路径呢?


可以使用一个dummy内核模块,在编译过程中把编译参数导出来,其中包含了头文件路径,编译参数等,用于bindgen生成代码。


Rust的target配置

内核模块和普通的程序相比,主要的不同在于:

  1. 内核模块是freestanding的,没有libc、内存分配也比较原始
  2. 内核模块对于异常处理等有特殊约定


rust提供了no_std机制,可以让rust代码编译成freestanding二进制;rust也提供了自定义target的方式,可以自定义声明生成二进制的规范。


内核模块的二进制约定

内核对内核模块有一些约定:

  • 通过.modinfo等section来声明模块信息
  • 提供init_module、cleanup_module来提供内核模块的安装和卸载功能


在这一块,rust提供了link_section来自定义section,也支持extern "C"来导出函数。

此外,这些底层的操作,可以由内核提供一些C语言宏来简化代码,Rust也提供了宏,可以用来做类似的事情。


一个小例子

说了这么多,我们来看一个带注释的例子:

#![no_std]
// no_std用于表示没有std库,即freestanding环境
extern crate alloc;
use alloc::borrow::ToOwned;
use alloc::string::String;
// 我们以printk为底层,提供了println
use linux_kernel_module::println;
// 这个struct代表内核模块
struct HelloWorldModule {
    message: String,
}
// 实现内核模块初始化方法
impl linux_kernel_module::KernelModule for HelloWorldModule {
    fn init() -> linux_kernel_module::KernelResult<Self> {
        println!("Hello kernel module from rust!");
        Ok(HelloWorldModule {
            message: "on the heap!".to_owned(),
        })
    }
}
// 提供内核模块卸载方法
impl Drop for HelloWorldModule {
    fn drop(&mut self) {
        println!("My message is {}", self.message);
        println!("Goodbye kernel module from rust!");
    }
}
// 通过kernel_module宏,export了内核模块的相关信息
linux_kernel_module::kernel_module!(
    HelloWorldModule,
    author: b"Fish in a Barrel Contributors",
    description: b"An extremely simple kernel module",
    license: b"GPL"
);


具体的构建和运行:

$ cd linux-kernel-module-rust/hello-world
$ RUST_TARGET_PATH=$(pwd)/.. cargo +nightly xbuild --target x86_64-linux-kernel-module
$ make
$ insmod helloworld.ko
$ rmmod helloworld
$ dmesg | tail -n 3
[521088.916091] Hello kernel module from rust!
[521174.204889] My message is on the heap!
[521174.204891] Goodbye kernel module from rust!


image.png

已在内核5.10.0-17-amd64上测试。

具体的代码以及相关配置,可以参考GitHub仓库:

https://github.com/robberphex/linux-kernel-module-rust


一些小细节

  • VSCode支持

由于rust-analyzer对于自定义target,多模块的支持不够,所以我们暂时需要手动配置下settings.json才能正常开发:

{
    "rust-analyzer.cargo.extraEnv": {
        "RUST_TARGET_PATH": "/root/linux-kernel-module-rust"
    },
    "rust-analyzer.cargo.target": "x86_64-linux-kernel-module",
    "rust-analyzer.server.extraEnv": {
        "RA_LOG": "lsp_server=debug",
        "RUST_TARGET_PATH": "/root/linux-kernel-module-rust"
    },
    "rust-analyzer.trace.server": "verbose",
    "rust-analyzer.linkedProjects": [
        "hello-world/Cargo.toml",
        "Cargo.toml"
    ],
}


  • 其他高级功能

比如字符设备、sysctl等功能,可以参考项目中相关的测试代码。


更多规划


原始项目是fishinabarrel/linux-kernel-module-rust,但目前提示使用rust-for-linux,已经archived。然而,考虑到目前旧版本内核还有很多,所以我重新修复了这个项目的一些环境,让大家在旧版本内核上能够用Rust编写内核模块。

相关文章
|
4月前
|
存储 Rust 编译器
30天拿下Rust之箱、包和模块
Rust语言使用模块系统来组织工程和代码。模块系统允许我们将相关的函数、类型、常量等组织在一起,形成一个逻辑上的单元。通过模块系统,我们可以隐藏实现细节,只暴露必要的接口,从而提高代码的可读性和可维护性。Rust的模块系统还支持路径依赖和重导出等功能,使得代码的组织更加灵活和方便。 Rust的模块系统中有三个非常重要的概念,分别是:箱(Crate)、包(Package)和模块(Module),下面逐一进行介绍。
43 1
30天拿下Rust之箱、包和模块
|
4月前
|
Rust 开发者
揭秘Rust编程:模块与包的终极对决,谁将主宰代码组织的新秩序?
【8月更文挑战第31天】在软件工程中,模块化设计能显著提升代码的可读性、可维护性和可重用性。Rust 作为现代系统编程语言,其模块和包管理机制为开发者提供了强有力的工具来组织代码。本文通过对比模块和包的概念及使用场景,探讨了 Rust 中的最佳实践。
40 2
|
4月前
|
开发者 API 开发框架
Xamarin 在教育应用开发中的应用:从课程笔记到互动测验,全面解析使用Xamarin.Forms构建多功能教育平台的技术细节与实战示例
【8月更文挑战第31天】Xamarin 作为一款强大的跨平台移动开发框架,在教育应用开发中展现了巨大潜力。它允许开发者使用单一的 C# 代码库构建 iOS、Android 和 Windows 应用,确保不同设备上的一致体验。Xamarin 提供广泛的 API 支持,便于访问摄像头、GPS 等原生功能。本文通过一个简单的教育应用示例——课程笔记和测验功能,展示了 Xamarin 在实际开发中的应用过程。从定义用户界面到实现保存笔记和检查答案的逻辑,Xamarin 展现了其在教育应用开发中的高效性和灵活性。
47 0
|
6月前
|
Rust 安全
Rust中的模块与路径管理
Rust中的模块与路径管理
|
6月前
|
Rust 编译器
Rust中的模块路径和pub关键字详解
Rust中的模块路径和pub关键字详解
|
7月前
|
Rust 开发者
Rust中的模块与包管理:构建高效、可扩展的代码库
本文详细阐述了Rust编程语言中模块与包管理的概念、特点和使用方法。通过深入了解模块与包的概念、组织方式、导入导出机制以及Rust的Cargo工具,我们将学会如何构建高效、可扩展的代码库,提高代码的可读性、可维护性和可重用性。
|
7月前
|
Rust
【一起学Rust · 项目实战】命令行IO项目minigrep——重构优化模块和错误处理
【一起学Rust · 项目实战】命令行IO项目minigrep——重构优化模块和错误处理
74 0
|
Rust 安全 Linux
如何使用 rust 写内核模块
近年来,Rust 语言以内存安全、高可靠性、零抽象等能力获得大量开发者关注,而这些特性恰好是内核编程中所需要的,所以我们看下如何用rust来写Linux内核模块。
324 4
如何使用 rust 写内核模块
|
Rust 编译器 Shell
Rust学习笔记之包、Crate和模块
1. Rust中包和 crate 推荐阅读指数 ⭐️⭐️⭐️⭐️⭐️ 2. 模块控制作用域与私有性 推荐阅读指数 ⭐️⭐️⭐️⭐️ 3. 路径用于引用模块树中的项 推荐阅读指数 ⭐️⭐️⭐️⭐️ 4. use 将名称引入作用域 推荐阅读指数 ⭐️⭐️⭐️⭐️ 5. 将模块分割进不同文件 推荐阅读指数 ⭐️⭐️⭐️
170 0
Rust学习笔记之包、Crate和模块
|
Rust Linux 开发工具
Linus Torvalds:Rust For Linux 或将被合并到 Linux 5.20 内核中
Linus Torvalds:Rust For Linux 或将被合并到 Linux 5.20 内核中
164 0
Linus Torvalds:Rust For Linux 或将被合并到 Linux 5.20 内核中