Kernel

Signer les modules noyau tiers dkms pour le Secure Boot sous Linux

Table des matières

Introduction



Debian, Ubuntu, Fedora, RHEL utilisent des signatures numériques approuvées par l'UEFI Secure Boot. Les binaires du chargeur de démarrage (comme GRUB) et le noyau fourni dans la distribution (et ses modules) sont signés avec des clés reconnues par les certificats de la plateforme UEFI préinstallées sur la plupart des cartes mères. Par conséquent, il n'est pas nécessaire de désactiver le Secure Boot pour installer et utiliser ces systèmes.

Cependant, les modules fournis sous forme dkms livrés dans les dépôts comme par exemple les pilotes NVidia, Broadcom, certains pilotes Realtek, ou des logiciels qui ont besoin de modules noyau pour fonctionner comme VirtualBox ... sont compilés sur la machine et ne sont pas signés. Ils ne sont donc pas chargés si le Secure Boot est actif (car oui, Secure Boot empêche de charger des modules non signés, c'est son rôle).

Pour info, dkms signifie Dynamic Kernel Module Support Framework. dkms compile les modules tiers, externes du noyau lors de leur installation ou si un nouveau noyau est installé. Cela assure que ces modules sont toujours disponibles, même après une mise à jour du noyau.

Plutôt que de désactiver ce mécanisme de sécurité, nous allons voir comment générer notre certificat et nos clés de signature et les importer dans l'UEFI de la machine.

Tous les modules (de type dkms) seront ensuite automatiquement signés lors de la compilation sans intervention manuelle.

Ce tutoriel est une adaptation de celui intitulé Fedora : Signer les modules noyau tiers kmod pour le Secure Boot mais s'appliquant aux modules compilés avec DKMS (qui est plus courant dans l'écosystème Linux)

Prérequis



Toutes les manipulations seront réalisées avec les droits root.
Ce tutoriel est réalisé sous Debian, mais les commandes (et les noms des paquets) seront similaire dans les autres distributions Linux.

Dans un premier temps, on installe les outils nécessaires pour la gestion des clés machines, et des modules dkms:
Code BASH :
apt install dkms mokutil openssl


Une fois fait, vous pouvez vérifier le statut du SecureBoot avec la commande :
Code BASH :
mokutil --sb-state


Sur ma machine, il est actif :
Code :
SecureBoot enabled


Exemple avec un module non signé



Cet exemple est pour la démonstration dans ce tutoriel, ne l'installez pas si vous n'en avez pas le besoin !

Dans cet exemple, j'installe juste le module r8125 (qui n'est donc pas signé) et présent dans le dépôt non-free :
Code BASH :
apt install r8125-dkms


Le module a été compilé et installé :
Code :
Building initial module for 6.1.0-25-amd64
Done.
r8125.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/6.1.0-25-amd64/updates/dkms/
depmod...
Traitement des actions différées (« triggers ») pour initramfs-tools (0.142) ...
update-initramfs: Generating /boot/initrd.img-6.1.0-25-amd64


Lorsque j'essaie de charger le module :
Code BASH :
modprobe r8125


J'ai une erreur car le module n'est pas signé et reconnu par ma machine :
Code :
modprobe: ERROR: could not insert 'r8125': Key was rejected by service


Génération des certificats et clés



Certains logiciels veulent que le dossier /var/lib/shim-signed/mok soit présent, donc on va mettre nos clés dedans
Code BASH :
mkdir -p /var/lib/shim-signed/mok
cd /var/lib/shim-signed/mok


Dans un premier temps, on va créer une clé et un certificat avec openssl d'une durée de 100 ans par exemple pour signer les modules :
Code BASH :
openssl req -nodes -new -x509 -newkey rsa:2048 -keyout mok.priv -outform DER -out mok.der -days 36500 -subj "/CN=$(hostname)/"

On utilise du RSA2048 car certains UEFI ne supportent pas correctement le RSA 4096

Deux fichiers sont créés :
/var/lib/shim-signed/mok/mok.priv : la clé privée pour signer les modules
/var/lib/shim-signed/mok/mok.der : la clé publique (certificat) pour vérifier la signature

Enregistrer les certificats et clés dans l'UEFI



Lançons l'import dans l'UEFI



On va ensuite enregistrer les éléments précédemment générés dans l'UEFI et le module Secure Boot.
Cela permettra au noyau Linux de faire confiance aux pilotes signés avec notre clé publique (certificat) :
Code BASH :
mokutil --import /var/lib/shim-signed/mok/mok.der


On va devoir entrer un mot de passe.
Il n'a pas besoin d'être très long ou complexe. On en aura juste besoin pour importer le certificat dans le secure boot.
Attention, on sera en qwerty pour la saisie, donc on fera simple !

Une fois fait, on va redémarrer le système :
Code BASH :
reboot


Validons l'import côté UEFI



Lorsque l'UEFI s'initialise, on est intercepté pour ajouter le certificat en attente.

secureboot-mok1


On valide par Entrée

Ensuite :

secureboot-mok2


Sélectionner Enroll MOK

secureboot-mok3


Puis Continue

secureboot-mok4


Puis Yes

secureboot-mok5


On saisit le mot de passe renseigné précédemment (rappel on est en qwerty)

secureboot-mok6


Puis Reboot

Paramétrer DKMS pour signer automatiquement les modules compilés



Après la compilation de modules avec DKMS, on a des scripts qui sont appelés (pour regénérer un inirtd par exemple avec dracut).
On va ajouter le chemin vers les clés précédemment générées pour automatiser la signature.

Vérifier la configuration de dkms :
Code BASH :
nano /etc/dkms/framework.conf


Par défaut, les clés utilisées sont dans les chemins suivants :
Code BASH :
mok_signing_key=/var/lib/dkms/mok.key
mok_certificate=/var/lib/dkms/mok.pub

Ces clés ont été générées automatiquement, ce ne sont pas celles qu'on a généré nous même et importées précédemment.

On va modifier et renseigner le chemin vers les clés :
Code BASH :
mok_signing_key=/var/lib/shim-signed/mok/mok.priv
mok_certificate=/var/lib/shim-signed/mok/mok.der


Tous les modules seront signés automatiquement maintenant

Installer ou réinstaller des modules



Installer de nouveaux modules



Maintenant, tous les modules "dkms" seront compilés et signés automatiquement avec notre clé, que SecureBoot connait.

Réinstaller des modules existants



Si on avait déjà des modules installés, on pourra les identifier via :
Code BASH :
dkms status


Dans l'exemple du tuto :
Code :
r8125/9.011.00, 6.1.0-25-amd64, x86_64: installed


On les réinstalle :
Code BASH :
dkms remove r8125/9.011.00 --all
dkms install r8125/9.011.00


Dans l'exemple de ce tuto avec le module r8125 :
Code :
Module r8125 9.011.00 is not installed for kernel 6.1.0-25-amd64 (x86_64). Skipping...
Deleting module r8125-9.011.00 completely from the DKMS tree.
Sign command: /usr/lib/linux-kbuild-6.1/scripts/sign-file
Signing key: /var/lib/shim-signed/mok/mok.priv
Public certificate (MOK): /var/lib/shim-signed/mok/mok.der
Creating symlink /var/lib/dkms/r8125/9.011.00/source -> /usr/src/r8125-9.011.00
Building module:
Cleaning build area...
make -j4 KERNELRELEASE=6.1.0-25-amd64 -C /lib/modules/6.1.0-25-amd64/build M=/var/lib/dkms/r8125/9.011.00/build......
Signing module /var/lib/dkms/r8125/9.011.00/build/r8125.ko
Cleaning build area.


On regénère aussi l'image initrd.

Pour les distributoons utilisant initramfs-tools (branche Debian) :
Code BASH :
update-initramfs -u


Distributions utilisant dracut :
Code BASH :
dracut --force


On peut charger le module manuellement avec modprobe :
Code BASH :
modprobe -v r8125


Ou on peut carrément reboot :
Code BASH :
reboot


Vérifier que les modules sont chargés



Si notre module est signé correctement, alors il est chargé par le système.

On pourra le constater avec la fameuse commande lsmod :
Code BASH :
lsmod | grep r8125


Ici, le module est bien chargé :
Code :
r8125                 237568  0



Signer des modules installés manuellement



Si vous n'avez pas de modules installés sous forme de "dkms", il est possible de signer les modules "manuellement".

Je prends dans cet exemple VirtualBox, mais installé avec le .deb du site Oracle.

Après avoir généré et importé les certificats et clés, on recherche le chemin du module :
Code BASH :
modinfo vboxdrv


Cela me renvoie :
Code :
filename:       /lib/modules/6.1.0-25-amd64/misc/vboxdrv.ko
version:        7.1.0 r164728 (0x00340001)
license:        GPL
description:    Oracle VirtualBox Support Driver
author:         Oracle and/or its affiliates
srcversion:     1D640EFCE74255CFEC18A1C
depends:        
retpoline:      Y
name:           vboxdrv
vermagic:       6.1.0-25-amd64 SMP preempt mod_unload modversions 
parm:           disabled:Disable automatic module loading (int)
parm:           force_async_tsc:force the asynchronous TSC mode (int)


Il existe un script pour signer les modules.

Sur Debian, son chemin est le suivant (pour un noyau 6.1) et est fourni par le paquet linux-kbuild :
Code BASH :
/usr/lib/linux-kbuild-6.1/scripts/sign-file


Sur Debian, son chemin est le suivant et il est fourni par le paquet linux-headers :
Code BASH :
/usr/src/linux-headers-$(uname -r)/scripts/sign-file


Sur Fedora, son chemin est le suivant et il est fourni par le paquet kernel-devel :
Code BASH :
/usr/src/kernels/$(uname -r)/scripts/sign-file


Pour signer notre module, on utilisera le script, avec les clés privées et publiques créées précédemment :
Code BASH :
$CHEMIN_DE_SIGNFILE/sign-file sha256 /var/lib/shim-signed/mok/mok.priv /var/lib/shim-signed/mok/mok.der $CHEMIN_DU_MODULE


Pour VirtualBox avec Debian :
Code BASH :
/usr/lib/linux-kbuild-6.1/scripts/sign-file sha256 /var/lib/shim-signed/mok/mok.priv /var/lib/shim-signed/mok/mok.der  /lib/modules/6.1.0-25-amd64/misc/vboxdrv.ko


Evidemment, ce sont des actions manuelles à faire à chaque mise à jour du noyau et recompilation du module !

On peut charger le module avec succès et vérifier que le module est signé :
Code BASH :
modinfo vboxdrv


Code :
filename:       /lib/modules/6.1.0-25-amd64/misc/vboxdrv.ko
version:        7.1.0 r164728 (0x00340001)
license:        GPL
description:    Oracle VirtualBox Support Driver
author:         Oracle and/or its affiliates
srcversion:     1D640EFCE74255CFEC18A1C
depends:        
retpoline:      Y
name:           vboxdrv
vermagic:       6.1.0-25-amd64 SMP preempt mod_unload modversions 
sig_id:         PKCS#7
signer:         debsecure
sig_key:        59:64:32:0C:5E:10:DF:ED:79:AD:BA:8C:6C:F9:4B:4E:6D:92:52:58
sig_hashalgo:   sha256
signature:      68:57:46:E2:83:0A:FE:AE:80:82:E6:6C:49:FE:D6:36:C1:3F:A6:D1:
                6C:F4:5D:B9:64:EA:97:4D:F2:4D:CE:A0:B3:C4:3A:8B:85:2D:81:3F:
                9E:6E:96:55:E2:59:55:05:92:BE:35:36:7B:3B:62:F7:82:F9:D6:71:
                21:5C:75:45:A3:D2:2D:90:4C:20:27:9F:18:09:65:27:2D:69:D3:12:
                ED:EF:8C:96:41:CB:C9:84:D6:14:B2:D5:AC:48:BE:91:47:94:E6:FC:
                FC:D4:BD:10:3A:76:AF:25:5D:26:94:30:FF:FB:FC:B7:80:F9:38:87:
                02:ED:D0:A9:DA:2B:2A:04:29:23:0F:5E:72:1C:A6:09:46:36:2D:C4:
                E0:E1:BC:14:D6:A6:C8:15:9C:53:05:5F:FA:AF:25:4F:43:F8:3E:60:
                FE:24:A8:B7:88:F7:8E:78:B5:20:DA:98:E4:06:A0:EE:71:8F:52:39:
                50:D0:D6:EB:13:8D:0F:BD:F8:1E:91:82:55:1F:D0:F2:28:E2:36:B5:
                00:B7:CE:CF:C5:9A:B5:63:A5:29:3A:34:F7:0C:D6:40:15:D2:3E:3E:
                DC:41:7B:6A:CE:FC:A1:82:6E:79:18:0A:19:E6:E7:CB:96:68:9D:6E:
                9B:99:AF:7D:A5:DD:09:F9:F0:4B:72:7D:58:20:B2:E1
parm:           disabled:Disable automatic module loading (int)
parm:           force_async_tsc:force the asynchronous TSC mode (int)
Cette page a été vue 5752 fois