Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save novafacing/b66ae432052081b1b2bede7103185147 to your computer and use it in GitHub Desktop.
Save novafacing/b66ae432052081b1b2bede7103185147 to your computer and use it in GitHub Desktop.
Building the Fedora Linux Kernel with Rust Support!

Building the Fedora Linux Kernel with Rust Support

I've been using Fedora Linux for a couple years now, and this week I wanted to write a kernel module for some reasons. Of course, I try to write all software I possibly can in Rust, and Linux recently has support for writing modules, including out of tree modules, in Rust! Great, so it should be really easy, just copy the rust-out-of-tree-module Makefile and Kbuild, run make, and insmod ourselves to success!

If it was that easy, we would have no blog post.

Building a Fedora Kernel

Because I'm on Fedora, my first idea was to follow the Fedora documentation for building the kernel as RPM packages. There is pretty decent documentation for doing this on the Fedora docs page.

If all you want to do is build RPM packages for the Linux Kernel exactly as it is maintained by Red Hat/Fedora maintainers, you can follow these directions. Unfortunately, we need to set a few configurations, which I naively tried to set in kernel-local, as the documentation instructs:

CONFIG_RUST=y
# CONFIG_RUST_DEBUG_ASSERTIONS is not set
CONFIG_RUST_OVERFLOW_CHECKS=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set

These configurations do not conflict with the upstream configurations for the same architecture/distribution, so they will work when we add them to kernel-local with the diff1.

Unfortunately, there is currently a bug with a fix hopefully landing soon which causes a build failure, and I couldn't figure out how to disable this selftest without setting:

CONFIG_X86_DECODER_SELFTEST=n

In the kernel-local file. Unfortunately this configuration does conflict with the upstream configurations, and causes an error from the script process_configs.sh about conflicting configurations:

Error: Mismatches found in configuration files for x86_64 x86_64-debug
Found # CONFIG_X86_DECODER_SELFTEST is not set, after generation, had CONFIG_X86_DECODER_SELFTEST n in Source tree
Error: Mismatches found in configuration files for x86_64 x86_64
Found # CONFIG_X86_DECODER_SELFTEST is not set, after generation, had CONFIG_X86_DECODER_SELFTEST n in Source tree
error: Bad exit status from /var/tmp/rpm-tmp.JNrTT1 (%prep)

This was a common error message when playing with configurations, both when building following the Fedora documentation, and when building the Fedora ARK kernel distribution.

So we bail out of trying to build RPM packages. This kernel is just going to be for my use anyway, so this is fine.

Building A Vanilla Kernel

Because the RPMs were a dead end, I ended up following the process recommended by the [Fedora Docs](docs page. First, install the dependencies as shown in the Fedora Docs. Then, we can get building.

This boils down to the following. Basically, we clone the kernel source, copy our running (since we are running Fedora already -- if you aren't, the docs linked there explain how to use dist-git to get a base configuration) configuration as the kernel configuration, enable Rust, disable the broken test, add a version string, and build!

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
cp /boot/config-`uname -r`* .config
sed -i 's/CONFIG_X86_DECODER_SELFTEST.*/CONFIG_X86_DECODER_SELFTEST=n/' .config
cat <<EOF >>.config
CONFIG_RUST=y
# CONFIG_RUST_DEBUG_ASSERTIONS is not set
CONFIG_RUST_OVERFLOW_CHECKS=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
EOF
sed -i '0,/EXTRAVERSION/s/EXTRAVERSION.*/EXTRAVERSION = -custom-rust/' Makefile
make oldconfig
make bzImage
make modules

If you don't have secure boot enabled, you can just run:

sudo make modules_install
sudo make install

If you do have secure boot enabled, you're going to need to create a keypair, register it as a Machine Owner Key (MOK), and sign the kernel with it. The Red Hat docs for this process are quite good, and we can follow them directly. You may also need to follow the "Secure Boot" section in the Fedora documentation linked above.

We need to sign both modules and the custom kernel, so we'll take care of both of those things. I think most people who are signing one kernel or module will probably need to sign more things, so I don't exactly follow the docs (which would have you generate your keys and such to the linux directory). First, we create two key pairs:

sudo efikeygen --dbdir /etc/pki/pesign \
            --self-sign \
            --kernel \
            --common-name 'CN=rhart-custom-kernel-key' \
            --nickname 'rhart-custom-kernel-key'
sudo efikeygen --dbdir /etc/pki/pesign \
            --self-sign \
            --module \
            --common-name 'CN=rhart-custom-module-key' \
            --nickname 'rhart-custom-module-key'

After generating the pairs, I created a directory for them and exported both public keys. You'll be prompted for a password for eac mokutil command, just make sure to remember that password because you will need it after a reboot.

mkdir ~/.certs
sudo certutil -d /etc/pki/pesign \
           -n 'rhart-custom-kernel-key' \
           -Lr \
           > ~/.certs/rhart-custom-kernel.cer
sudo certutil -d /etc/pki/pesign \
           -n 'rhart-custom-module-key' \
           -Lr \
           > ~/.certs/rhart-custom-module.cer
sudo pk12util -o ~/.certs/rhart-custom-module.p12 \
            -n 'rhart-custom-module-key' \
            -d /etc/pki/pesign
sudo openssl pkcs12 -in ~/.certs/rhart-custom-module.p12 \
            -out ~/.certs/rhart-custom-module.priv \
            -nocerts \
            -nodes
sudo mokutil --import ~/.certs/rhart-custom-kernel.cer
sudo mokutil --import ~/.certs/rhart-custom-module.cer

Then, reboot your machine:

sudo reboot now

On reboot, you'll get a big scary blue screen for MOK. Select the "Install Key" option (which may also be called "Enroll MOK"), select your key nickname, and enter the password. Do it a second time with the other key. After that, select the reboot option to reboot with your keys registered.

Now that we can sign our kernel, go ahead and run:

sudo make install

This installs the kernel to (in my case), /boot/vmlinuz-6.7.0-rc1+. To sign it, I just ran:

sudo pesign --certificate 'rhart-custom-kernel-key' \
    --in /boot/vmlinuz-6.7.0-rc1+ \
    --sign \
    --out /boot/vmlinuz-6.7.0-rc1+.signed
mv /boot/vmlinuz-6.7.0-rc1+.signed /boot/vmlinuz-6.7.0-rc1+

You may not need them, but if you want to install (and sign) external modules, run:

sudo make modules_install

The modules will be signed with a default key.

On reboot, select the new kernel from the list and boot into it.

If you can boot, congrats!

Building Our Module

Go ahead and clone the Rust out of tree repo and build the module:

git clone /https://github.com/Rust-for-Linux/rust-out-of-tree-module
make

If you have secure boot and SELinux and all that jazz off, you can just:

sudo insmod

Otherwise, you'll see:

insmod: ERROR: could not insert module rust_out_of_tree.ko: Key was rejected by service

So we sign the module:

sudo /path/to/your/repo/linux/scripts/sign-file sha256 \
 ~/.certs/rhart-custom-module.priv \
 ~/.certs/rhart-custom-module.cer \
 rust_out_of_tree.ko

And now we can load it!

Enjoy the Rust kernel development :)

diff --git a/kernel-local b/kernel-local
index 8c32be5be..ad8b799e1 100644
--- a/kernel-local
+++ b/kernel-local
@@ -1,2 +1,4 @@
-# This file is intentionally left empty in the stock kernel. Its a nicety
-# added for those wanting to do custom rebuilds with altered config opts.
+CONFIG_RUST=y
+# CONFIG_RUST_DEBUG_ASSERTIONS is not set
+CONFIG_RUST_OVERFLOW_CHECKS=y
+# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set
diff --git a/kernel.spec b/kernel.spec
index 9879fa747..490a380e5 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -159,7 +159,7 @@ Summary: The Linux kernel
 #  to build the base kernel using the debug configuration. (Specifying
 #  the --with-release option overrides this setting.)
 %define debugbuildsenabled 1
-# define buildid .local
+%define buildid .local
 %define specrpmversion 6.7.0
 %define specversion 6.7.0
 %define patchversion 6.7

Footnotes

@novafacing
Copy link
Author

Now that nightly is 1.76+ you may need to rustup toolchain install stable, rustup default stable, rustup component add rust-src

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment