User:GeneWiki
Signed [[1]] Kernel modules provide a mechanism for the kernel to verify the integrity of a module.
Overview
The Linux Kernel distinguishes and keeps separate the verification of modules from requiring or forcing modules to verify before allowing them to be loaded. Kernel modules fall into 2 classes:
- Standard 'in tree' modules which come with the kernel
- source and are compiled during the normal kernel build.
- Out of tree modules which are not part of the kernel source distribution:
- Built outside of the kernel tree
- Require kernel headers package for each kernel they are to be built for. They can be built manually for a specific kernel and packaged - or they can be built whenever needed using dkms
- Examples of such packages, provided by arch, include virtualbox and wireguard.
The kernel can be enabled to always verify modules, and it then reports any failures to standard logs, the choice to permit the loading and use of a module which does not verify can be either compiled in to kernel or turned on at run time using a command line option to kernel boot command as explained below.
How to sign kernel modules using a custom kernel
The starting point is based on a custom kernel package as outlined in this article Arch_Build_System. We will modify the build to:
- Sign the standard in tree kernel modules
- Provide what is needed to have signed out of tree modules and for the kernel to verify those modules.
- In tree modules signed during the standard kernel build process.
- The standard kernel build creates a fresh public/private key pair on each build.
- Out of tree modules are signed and the associated public key is compiled in to the kernel.
- We will create a separate public/private key pair on each build.
Summary of what needs to be done
Want
Each kernel build needs to made aware of the key/cert being used. These change with each new kernel build : Kernel build now has additional config : CONFIG_SYSTEM_TRUSTED_KEYS="/path/to/oot_signing_keys.pem" By installing in current module dir then cleaning is automatic install certs in /usr/lib/modules/<kernel-vers>-<build>/certs-local
Kernel Config
In addition the following config options should be set manually editing the 'config' file, or via: % make menuconfig:in the linux 'src' area and subsequently copying the updated '.config' file back to the build file 'config'
Enable Loadable module suppot ---> Module Signature Verification - activate CONFIG_MODULE_SIG=y Require modules to be validly signed -> leave off CONFIG_MODULE_SIG_FORCE=n This allows the decision to enforce verified modules only as boot command line. If you're comfortable all is working then by all means change this to 'y' Command line version of this is : module.sig_enforce=1 Automatically sign all modules - activate Which hash algorithm -> SHA-512 Compress modules on installation - activate Compression algorithm (XZ) Allow loading of modules with missing namespace imports - set to no
Boot Command Line
Once you're comfortable things working well you can enable Boot time command to force only verified modules allowed: module.sig_enforce=1
Tools needed
kernel build package
In the directory where the kernel package is built: % mkdir certs-local This dir will have the tools to create the keys, as well as signing kernel modules. Put the 4 files into certs-local: fix_config.sh x509.oot.genkey genkeys.sh sign_manual.sh
The files genkeys.sh and its config x509.oot.genkey are used to create key pairs. the file fix_config.sh is run after that to provide the kernel with the key info by updating the config file used to build the kernel. The script sign_manual will be used to sign out of tree kernel modules. genkeys.sh will create the key pairs in a dir named by date-time. It also creates file 'current_key_dir' with that dir name and a soft link 'current' to the same dir with the 'current' key pairs.
dkms support
% mkdir certs-local/dkms Add 2 files to the dkms dir: kernel-sign.conf kernel-sign.sh These will be installed in /etc/dkms and provide a mechanism for dkms to automatically sign modules (using the local key above) - this is the reccommended way to sign kernel modules. As explained, below - once this is installed - all that is needed to have dkms automatically sign modules is to make a soft link: % cd /etc/dkms % ln -s kernel-sign.conf <package-name> e.g. % ln -s kernel-sign.conf virtualbox The link creation n easily be added to an arch package to simplify further.
Modify PKGBUILD
We need to make changes to kernel build as follows:
prepare()
prepare() { msg2 "Rebuilding local signing key..." cd ../certs-local ./genkeys.sh msg2 "Updating kernel config with new key..." ./fix_config.sh ../config cd ../src ... }
_package-headers()
_package-headers() { ... # # Out of Tree Module signing # This is run in the kernel source / build directory # msg2 "Local Signing certs for out of tree modules..." certs_local_src="../../certs-local" key_dir=$(<${certs_local_src}/current_key_dir) certs_local_dst="${builddir}/certs-local" signer="sign_manual.sh" mkdir -p ${certs_local_dst} rsync -a $certs_local_src/{current,$key_dir,$signer} $certs_local_dst/ # dkms tools dkms_src="$certs_local_src/dkms" dkms_dst="${pkgdir}/etc/dkms" mkdir -p $dkms_dst rsync -a $dkms_src/{kernel-sign.conf,kernel-sign.sh} $dkms_dst/ }
Files Required
i.e.
chmod +x certs-local/*.sh certs-local/dkms/*.sh
certs-local/fix_config.sh
#!/bin/bash # # Arg: config file # # Update kernel config : CONFIG_SYSTEM_TRUSTED_KEYS to use current keys # Config="$1" KeyDir=$(<current_key_dir) sed -e "s|^CONFIG_SYSTEM_TRUSTED_KEYS=.*$|CONFIG_SYSTEM_TRUSTED_KEYS=\"../../certs-local/$KeyDir/signing_key.pem\"|" < $Config > $Config.tmp mv $Config.tmp $Config exit 0
certs-local/x509.oot.genkey
[ req ] default_bits = 4096 distinguished_name = req_distinguished_name prompt = no string_mask = utf8only x509_extensions = myexts [ req_distinguished_name ] #O = Unspecified company CN = Out of tree kernel module signing key #emailAddress = unspecified.user@unspecified.company [ myexts ] basicConstraints=critical,CA:FALSE keyUsage=digitalSignature subjectKeyIdentifier=hash authorityKeyIdentifier=keyid
certs-local/genkeys.sh
#!/bin/bash # # Create new pub/priv key pair for signing out of tree kernel modules. # # Each key pair is stored by date-time # Dt=$(date +'%Y%m%d-%H%M') mkdir -p $Dt KernKey="${Dt}/signing_key.pem" PrivKey="${Dt}/signing_prv.key" KernCrt="${Dt}/signing_crt.crt" openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config ./x509.oot.genkey \ -outform PEM -out $KernKey -keyout $KernKey chmod 0600 $KernKey openssl pkey -in $KernKey -out $PrivKey openssl x509 -outform der -in $KernKey -out $KernCrt rm -f current; ln -s $Dt current rm -f current_key_dir echo "$Dt" > ./current_key_dir exit 0
certs-local/dkms/kernel-sign.conf
# # Installed as /etc/dkms/kernel-sign.conf # # link this to any module to be signed # # e.g. ln -s /etc/dkms/kernel-sign.conf /etc/dkms/virtualbox.conf POST_BUILD=../../../../../../etc/dkms/kernel-sign.sh
certs-local/dkms/kernel-sign.sh
#!/bin/bash # # Installed in /etc/dkms/kernel-sign.sh # # This is called via POST_BUILD for each module # We use this to sign in the dkms build directory. # cd ../$kernelver/$arch/module/ #SIGN=$kernel_source_dir/certs-local/sign_manual.sh SIGN=/usr/lib/modules/$kernelver/build/certs-local/sign_manual.sh if [ -f $SIGN ] ;then list=$(/bin/ls -1 *.ko *.ko.xz 2>/dev/null) if [ "$list" != "" ] ; then for mod in $list do echo "DKMS: Signing kernel ($kernelver) module: $mod" $SIGN "$mod" done fi else echo "kernel $kernelver doesn't have out of tree module signing tools" echo "skipping signing out of tree modules" fi