Skip to content

Instantly share code, notes, and snippets.

@xenithorb
Last active November 16, 2021 07:49
Show Gist options
  • Save xenithorb/df08970b9e70bb3c6576e1fd91460afe to your computer and use it in GitHub Desktop.
Save xenithorb/df08970b9e70bb3c6576e1fd91460afe to your computer and use it in GitHub Desktop.
Akmod kernel module auto-signer for kernel upgrades on Fedora
#!/bin/bash
#
# /etc/kernel/postinst.d script to sign akmods kmods after kernel upgrade
#
# Author: Michael Goodwin Date: 2016-09-21
# 1. Copy this script to /etc/kernel/postinst.d/ and `chmod +x` it
#
# 2. Create signing keys (store these somewhere useful and safe):
# $ mkdir -p /etc/pki/tls/private/mok
# $ cd !$
# $ openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv \
# -outform DER -out MOK.der -nodes -days 36500 -subj "/CN=Descriptive name/"
#
# 3. Replace PRIVATE_KEY and CERTIFICATE variables below with the
# key/cert paths from above. (Unless you kept the same paths)
#
# 4. Run the script as root to do a first-sign of the modules
#
# 5. Import the new certificate into MOK (one time thing):
# $ sudo mokutil --import MOK.der
#
# 6. Reboot and follow the instructions to authorize the key:
# https://sourceware.org/systemtap/wiki/SecureBoot
#
#set -x
KMOD_RPM_DIR=/var/cache/akmods
KERNEL_VER="${1:-$(ls -1 /usr/lib/modules | sort -V | tail -n1)}"
SIGN_SCRIPT="/usr/src/kernels/${KERNEL_VER}/scripts/sign-file"
PRIVATE_KEY=/etc/pki/tls/private/mok/MOK.priv
CERTIFICATE=/etc/pki/tls/private/mok/MOK.der
(
# Wait on backgrounded akmods build and install to finish
count=
while pgrep -f -- '/usr/sbin/akmods --from-kernel-posttrans' >/dev/null; do
sleep 1
(( count++ ))
(( count >= 300 )) && exit
done
# Find all kernel modules packaged by akmods
get_ko_array() {
readarray -t kmod_ko_array < <(
find "${KMOD_RPM_DIR}" -name "*${KERNEL_VER}*.rpm" -exec sh -c 'rpm -qlp "{}" | grep ".ko$"' \;
)
}
# Build the modules if we don't find anyway
get_ko_array
if [[ ! $kmod_ko_array ]]; then
akmods --kernels "${KERNEL_VER}" &&
get_ko_array
fi
# Sign all the modules from akmods
for ((i=0; i<${#kmod_ko_array[@]}; i++)); do
if ! strings "${kmod_ko_array[i]}" | tail -n1 | grep -q '~Module signature appended~'; then
"$SIGN_SCRIPT" sha256 "$PRIVATE_KEY" "$CERTIFICATE" "${kmod_ko_array[i]}"
fi
# uncomment this to strip the cert
# strip --strip-debug "${kmod_ko_array[i]}"
done
)&
wait; exit 0
@BlacCello
Copy link

Thank you very much! For everyone who is coming here: The script still works for Fedora 32 :)

@EliaGeretto
Copy link

@xenithorb Could you please attach a license to this code?

@larsks
Copy link

larsks commented Jun 25, 2021

It's not necessary to poll the akmods process using pgrep like this. Since the background akmods is started as a systemd service (see /usr/lib/kernel/install.d/95-akmodsposttrans.install), we can just install an drop-in config for that service that adds an additional ExecStart. See e.g. https://github.com/larsks/akmod-sign-modules for one way of implementing this.

@xenithorb
Copy link
Author

It's not necessary to poll the akmods process using pgrep like this. Since the background akmods is started as a systemd service (see /usr/lib/kernel/install.d/95-akmodsposttrans.install), we can just install an drop-in config for that service that adds an additional ExecStart. See e.g. https://github.com/larsks/akmod-sign-modules for one way of implementing this.

Fair point! This is obviously quite old and was from when I had a discrete NVIDIA GPU. Well, as it turns out, my shiny new laptop now has one once again after a few years of being AMD-only (for this very reason). So, I might have to polish this up and see if it still works.

@xenithorb Could you please attach a license to this code?

Certainly, let me do the above and then I'll republish it with an MIT most likely.

@thesourcehim
Copy link

This script does not work as expected in fedora 34. It only signs modules correctly if run manually. If run automatically from postinst.d here's what happens: the script is run right after new kernel is installed, but before dnf exits. Because of this akmod build does not even start because it is only started by systemd-inhibit after dnf transaction is fully finished. So this script just waits for 5 minutes for nothing and then does nothing, because all akmod modules will be installed only after this script and dnf finish execution.

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