[Ubuntu] RustでLinux kernel モジュールを開発する

2023.05.30

Introduction

Linux kernelの6.2からRustでカーネル開発をするための基本的なサポートが導入されましたが、
メジャーなディストリビューションは6.2をデフォルトで搭載していませんでした。
なのでRustカーネルを試そうとした場合、
カーネルのソース持ってきてカーネルビルド関連のソフトウェアやライブラリをインストールし、
Rust関連のオプションつけてビルドしなおして
Rustで書いたカーネルモジュールをビルドして
QEMUとかUTMとかでようやく動作確認ができます。 
とりあえずHelloWorldするだけでも、かなり面倒です。

しかし先日、Ubuntu 23.04 ⁠Lunar Lobsterがリリースされました。
これは標準でLinux Kernel 6.2を搭載しているので、面倒な手順を踏まなくても
Rust製のLinux kernelが動きます。

また、素晴らしいことに⁠Lunar LobsterのEC2のイメージ(Community AMI)の
存在を同僚に教えてもらいました。
(ubuntu/images/hvm-ssd/ubuntu-lunar-23.04-amd64-server-20230425,ami-039bc9bfd44dc9659)

今回は⁠Lunar LobsterのAMI Imageをつかって
ここを参考に、
RustでLinux kernelをビルドして動かしてみます。

Try

EC2でUbuntu 23の起動

まずは⁠Lunar LobsterをEC2で起動します。
東京リージョンで⁠Lunar LobsterのAMIを指定して起動します。

ログインして環境設定

sshログインします。
いつものクセでec2@〜とやらないように。

% ssh -i <pemのパス> ubuntu@<Public IP>

サーバにログインしたらapt updateして必要モジュールのインストールをします。  

% sudo apt update
% sudo apt install rustc-1.62 rust-1.62-src rustfmt-1.62 \
   bindgen-0.56 llvm clang gcc make linux-headers-`uname -r`

必要なのはこれだけ。
もしmake時にエラーがでたら
bisonとかflexとかいれる必要があるかも。

次にRustのカーネルモジュールを作成します。

% mkdir rust_kernel && cd rust_kernel
% vi hello_rust.rs

シンプルなHello World。  

// SPDX-License-Identifier: GPL-2.0

//! Rust Kernel Module hello world example.

use kernel::prelude::*;

module! {
    type: HelloRust,
    name: "hello_rust",
    author: "Your Name <your email address>",
    description: "Rust Kernel Module hello world example",
    license: "GPL",
}

struct HelloRust {
}

impl kernel::Module for HelloRust {
    fn init(_module: &'static ThisModule) -> Result<Self> {
        pr_info!("Hello World Kernel Module from Rust\n");
        Ok(HelloRust { })
    }
}

impl Drop for HelloRust {
    fn drop(&mut self) {
        pr_info!("Goodbye Kernel Module from Rust\n");
    }
}

Makefileも作成します。

vi Makefile
NAME=hello_rust

ifndef KERNELRELEASE
ifndef KDIR
KDIR:=/lib/modules/`uname -r`/build
endif
PWD := $(shell pwd)

rust_flags=CROSS_COMPILE=x86_64-linux-gnu- HOSTRUSTC=rustc-1.62 RUSTC=rustc-1.62 BINDGEN=bindgen-0.56 RUSTFMT=rustfmt-1.62 RUST_LIB_SRC=/usr/src/rustc-1.62.1/library

all:
	@$(MAKE) $(rust_flags) -C $(KDIR) M=$(PWD) modules

install:
	@$(MAKE) $(rust_flags) -C $(KDIR) M=$(PWD) modules_install

clean:
	@rm -f *.o *.ko *.mod* .*.cmd *.d Module.symvers modules.order
	@rm -rf .tmp_versions

else
obj-m := $(NAME).o
endif

※ご指摘により修正。ありがとうございます。

準備はこれだけです。簡単ですね。

makeしましょう。

% make
make[1]: Entering directory '/usr/src/linux-headers-6.2.0-1003-aws'
  RUSTC [M] /home/ubuntu/kernel/hello_rust.o
  MODPOST /home/ubuntu/kernel/Module.symvers
  CC [M]  /home/ubuntu/kernel/hello_rust.mod.o
  LD [M]  /home/ubuntu/kernel/hello_rust.ko
  BTF [M] /home/ubuntu/kernel/hello_rust.ko
Skipping BTF generation for /home/ubuntu/kernel/hello_rust.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.2.0-1003-aws'

ファイルが生成されてます。

% ls
Makefile        hello_rust.ko   hello_rust.mod.c  hello_rust.o   modules.order
Module.symvers  hello_rust.mod  hello_rust.mod.o  hello_rust.rs

モジュールをロードした後、lsmodで確認してみましょう。
問題ないようです。

% sudo insmod hello_rust.ko

sudo lsmod | grep hello
hello_rust             16384  0

dmesgで確認します。ちゃんと実行ログも出てますね。

% sudo dmesg | tail -1
[63004.531176] hello_rust: Hello World Kernel Module from Rust

おわったらrmmodでモジュールを削除しておきます。

% sudo rmmod hello_rust

使い終わったらEC2インスタンスも停止しておきましょう。

Summary

今回はUbuntu 23でRustを使ってカーネルモジュールのビルドと実行を確認してみました。
以前に試したことがある人は、
とても簡単にカーネルの実行まで確認できたことがわかると思います。
このように簡単に試せる環境があると、
Rustでのカーネル開発も少し手が出しやすくなるのではないでしょうか。

ちなみに、最初はM1 MacでUTMつかってubuntu23を起動してやろうとしてましたが、
モジュールビルド後にinsmodするとinvalid formatで動きませんでした。
こっちもなんとか動かしたいところなので、引き続きトライします。

[2023/06/05 追記]
UTM 4.1.5を使用することで、M1 Mac上でも
本稿の手順でRust Kernelモジュールを動作させることができました。

References