Product SiteDocumentation Site

8.10. Compilare un kernel

I kernel forniti da Debian includono il maggior numero possibile di funzionalità, così come il massimo numero di driver, per coprire lo spettro più ampio di configurazioni hardware esistenti. Ecco perché alcuni utenti preferiscono ricompilare il kernel per includere unicamente ciò di cui necessitano. Ci sono due ragioni per questa scelta. Primo, questo può ottimizzare il consumo di memoria perché il codice del kernel anche se non viene mai utilizzato occupa memoria senza motivo (e non viene mai posto nello spazio di swap, dato che utilizza la vera RAM), cosa che può diminuire le prestazioni complessive del sistema. Inoltre un kernel compilato localmente può anche limitare i rischi di sicurezza poiché solo una frazione del codice del kernel è compilato ed eseguito.
Ricompilare il kernel è inoltre necessario se si vuole utilizzare certe funzionalità che sono disponibili solo come patch (e non sono incluse nella versione standard del kernel).

8.10.1. Introduzione e prerequisiti

Non stupisce che Debian gestisca il kernel sotto forma di pacchetti, diversamente da come i kernel sono stati compilati ed installati tradizionalmente. Poiché il kernel rimane sotto il controllo del sistema di pacchettizazione può essere rimosso in modo pulito, o distribuito su diverse macchine. Inoltre, gli script associati con questi pacchetti automatizzano l'interazione con il bootloader ed il generatore initrd.
I sorgenti di Linux contengono tutto il necessario per creare un pacchetto Debian del kernel. Tuttavia è necessario installare build-essential per assicurarsi di avere gli strumenti necessari per creare il pacchetto Debian. Inoltre, la fase di configurazione del kernel richiede il pacchetto libncurses-dev (precedentemente libncurses5-dev, che ora è un pacchetto di transizione). Infine, il pacchetto fakeroot che permette di creare il pacchetto Debian senza bisogno dei diritti di amministratore.

8.10.2. Ottenere i sorgenti

Come qualiasi cosa che può essere utile in un sistema Debian, i sorgenti del kernel Linux sono disponibili in un pacchetto. Per ottenerli, basta installare il pacchetto linux-source-versione. Il comando apt search ^linux-source elenca le varie versioni del kernel pacchettizate da Debian. L'ultima versione è disponibile nella distribuzione Unstable: è possibile ottenerla senza troppi rischi (specialmente se il proprio APT è configurato secondo le istruzioni presenti in Sezione 6.2.6, «Lavorare con più distribuzioni»). Da notato che il codice sorgente contenuto in questi pacchetti non corrisponde precisamente a quello pubblicato da Linus Torvalds e dagli sviluppatori del kernel: come tutte le distribuzioni, Debian applica una serie di patch che potrebbero (o non) essere inglobate nella versione originale di Linux. Queste modifiche includono backport di /correzioni/caratteristiche/driver dalle versioni più recenti del kernel, nuove funzionalità non ancora (interamente) incluse in Linux e, talvolta, anche cambiamenti specifici di Debian.
Il resto di questa sezione si concentra sulla versione 5.10 del kernel Linux, ma gli esempi possono, natualmente, essere adattati alla particolare versione del kernel che si desidera.
Supponiamo che il pacchetto linux-source-5.10 sia installato. Contiene /usr/src/linux-source-5.10.tar.xz, un archivio compresso dei sorgenti del kernel. Si devono estrarre questi file in una nuova directory (non direttamente in /usr/src/, poiché non c'è bisogno di permessi speciali per compilare un kernel Linux): ~/kernel/ è appropriato.
$ mkdir ~/kernel; cd ~/kernel
$ tar -xaf /usr/src/linux-source-5.10.tar.xz
Per compilare un kernel dai sorgenti originali, basta scaricare il tarball della versione desiderata da kernel.org, verificarne l'integrità dopo aver importato la chiave dei manutentori del kernel e procedere come descritto nei capitoli seguenti.

$ wget https://kernel.org/pub/linux/kernel/v5.x/linux-5.10.62.tar.xz
[..]
$ wget https://kernel.org/pub/linux/kernel/v5.x/linux-5.10.62.tar.sign
[..]
$ unxz -c linux-5.10.62.tar.xz | gpg --verify linux-5.10.62.tar.sign -
gpg: Signature made Fri 03 Sep 2021 10:11:35 AM CEST
gpg:                using RSA key 647F28654894E3BD457199BE38DBBDC86092693E
gpg: Good signature from "Greg Kroah-Hartman <gregkh@linuxfoundation.org>" [unknown]
gpg:                 aka "Greg Kroah-Hartman (Linux kernel stable release signing key) <greg@kroah.com>" [unknown]
gpg:                 aka "Greg Kroah-Hartman <gregkh@kernel.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 647F 2865 4894 E3BD 4571  99BE 38DB BDC8 6092 693E

8.10.3. Configurare il kernel

I passi successivi consistono nella configurazione del kernel secondo le proprie necessità. La procedura esatta dipende dagli obiettivi.
Quando si ricompila una versione più recente del kernel (eventualmente con una patch aggiuntiva), la configurazione sarà probabilmente mantenuta il più vicino possibile a quella proposta da Debian. In questo caso, piuttosto che riconfigurare tutto da zero, è sufficiente copiare il file /boot/config-versione (la versione è quella del kernel attualmente in uso, che può essere trovata con il comando uname -r) in un file .config nella directory contenente i sorgenti del kernel. In questo caso, assicurarsi di leggere il riquadro SUGGERIMENTO Manca debian/certs/debian-uefi-certs.pem.
$ cp /boot/config-5.10.0-8-amd64 ~/kernel/linux-source-5.10/.config
Se non si necessita di cambiare la configurazione, è possibile fermarsi qui e saltare alla Sezione 8.10.4, «Compilazione e creazione del pacchetto». Se invece è necessario modificarla, o se si è deciso di riconfigurare tutto da zero, è necessario prendersi del tempo per configurare il kernel. Ci sono varie interfacce dedicate nella directory dei sorgenti del kernel che possono essere richiamate utilizzando il comando make target, dove target sarà uno dei valori descritti di seguito.
make menuconfig compila ed esegue un'interfaccia testuale (ecco perché è richiesto il pacchetto libncurses-dev) che consente la navigazione tra le opzioni disponibili in una struttura gerarchica. Premendo il tasto Spazio si cambia il valore delle opzioni selezionate, ed Invio conferma il bottone selezionato in basso sullo schermo; Select rimanda al sotto-menu selezionato; Exit chiude la finestra corrente e torna indietro alla gerarchia, Help visualizzerà informazioni maggiormente dettagliate sul ruolo dell'opzione selezionata. Le frecce consentono di muoversi tra la lista delle opzioni e dei bottoni. Per uscire dal programma di configurazione, scegliere Exit dal menu principale. Il programma offrirà di salvare le modifiche effettuate; accettare se si è soddisfatti delle proprie scelte.
Altre interfacce hanno caratteristiche simili, ma funzionano con interfacce grafiche più moderne, come make xconfig che usa un'interfaccia grafica Qt e make gconfig che usa GTK+. La prima richiede qtbase5-dev, mentre la seconda dipende da libglade2-dev e libgtk2.0-dev.
Quando si utilizza una di queste interfacce di configurazione, è sempre una buona idea partire da una configurazione predefinita ragionevole. Il kernel fornisce tali configurazioni in arch/arch/configs/*_defconfig e si può attivare la configurazione selezionata con un comando come make x86_64_defconfig (in caso di un PC a 64-bit) opuure make i386_defconfig (in caso di un PC a 32-bit).

8.10.4. Compilazione e creazione del pacchetto

Una volta che la configurazione del kernel è pronta, un semplice make deb-pkg genererà fino a 5 pacchetti Debian:
linux-image-versione
contiene l'immagine del kernel ed i relativi moduli,
linux-headers-versione
contiene i file di intestazione (header) necessari per costruire i moduli esterni,
linux-firmware-image-versione
contiene i firmware necessari per alcuni driver (questo pacchetto potrebbe mancare quando si compilano i sorgenti del kernel forniti da Debian),
linux-image-versione-dbg
contiene i simboli di debug per l'immagine del kernel ed i suoi moduli (creato solo se CONFIG_DEBUG_INFO=y), e
linux-libc-dev
contiene le intestazioni (header) rilevanti per alcune librerie dello spazio utente, come GNU glibc.
La versione è definita dalla concatenazione della versione upstream (definita dalle variabili VERSION, PATCHLEVEL, SUBLEVEL e EXTRAVERSION nel Makefile ), del parametro di configurazione LOCALVERSION e della variabile d'ambiente LOCALVERSION. La versione del pacchetto riutilizza la stessa stringa di versione con una revisione aggiunta che viene incrementata regolarmente (e memorizzata in .version), a meno che non la si sovrascriva con la variabile d'ambiente KDEB_PKGVERSION.
$ make deb-pkg LOCALVERSION=-falcot KDEB_PKGVERSION=$(make kernelversion)-1
[...]
$ ls ../*.deb
../linux-headers-5.10.46-falcot_5.10.46-1_amd64.deb
../linux-image-5.10.46-falcot_5.10.46-1_amd64.deb
../linux-image-5.10.46-falcot-dbg_5.10.46-1_amd64.deb
../linux-libc-dev_5.10.46-1_amd64.deb
L'intero processo richiede circa 20 GB di spazio libero, almeno 8 GB di RAM e diverse ore di compilazione (utilizzando un core) per un kernel Debian standard amd64. Questi requisiti possono essere drasticamente ridotti disabilitando le informazioni di debug con CONFIG_DEBUG_INFO=n, ma questo renderà impossibile tracciare gli errori del kernel ("oops") usando gdb ed impedirà, inoltre, la creazione del pacchetto linux-image-version-dbg.

8.10.5. Compilare moduli esterni

Alcuni moduli sono mantenuti fuori dal kernel ufficiale Linux. Per usarli, è necessario compilarli parallelamente al kernel corrispondente. Alcuni moduli comuni di terze parti sono forniti da Debian in pacchetti dedicati, come vpb-driver-source (moduli aggiuntivi per hardware telefonico Voicetronix) o leds-alix-source (driver per schede ALIX 2/3 di PCEngines).
Questi pacchetti sono molti e variegati, apt-cache rdepends module-assistant$ può mostrarne l'elenco fornito da Debian. Comunque una lista completa non sarebbe particolarmente utile visto che non c'è una ragione particolare per compilare moduli esterni se non quando si sa di averne bisogno. In questi casi la documentazione del dispositivo dettaglia tipicamente i moduli specifici di cui necessita per funzionare su Linux.
Per esempio, diamo un'occhiata al pacchetto dahdi-source: dopo l'installazione, in /usr/src/ viene memorizzato un file .tar.bz2 dei sorgenti del modulo. Anche se si potrebbe estrarre manualmente l'archivio tarball e compilare il modulo, in pratica si preferisce automatizzare il tutto utilizzando l'infrastruttura DKMS (Dynamic Kernel Module Support). La maggior parte dei moduli offrono l'integrazione DKMS nei pacchetti che terminano con il suffisso -dkms. Nel nostro caso, l'installazione di xtables-addons-dkms è tutto ciò che serve per compilare il modulo del kernel per il kernel corrente a condizione che si abbia il pacchetto linux-headers-* corrispondente al kernel installato. Per esempio, se si utilizza linux-image-amd64, si dovrebbe installare anche linux-headers-amd64.
$ sudo apt install dahdi-dkms
[...]
Setting up dkms (2.8.4-3) ...
Setting up linux-headers-5.10.0-8-amd64 (5.10.46-4) ...
/etc/kernel/header_postinst.d/dkms:
dkms: running auto installation service for kernel 5.10.0-8-amd64:.
Setting up dahdi-dkms (1:2.11.1.0.20170917~dfsg-7.4) ...
Loading new dahdi-2.11.1.0.20170917~dfsg-7.4 DKMS files...
Building for 5.10.0-8-amd64
Building initial module for 5.10.0-8-amd64
Done.

dahdi_dummy.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.10.0-8-amd64/updates/dkms/

dahdi_dynamic_eth.ko:
Running module version sanity check.
 - Original module
   - No original module exists within this kernel
 - Installation
   - Installing to /lib/modules/5.10.0-8-amd64/updates/dkms/

[...]
DKMS: install completed.
$ sudo dkms status
dahdi, 2.11.1.0.20170917~dfsg-7.4, 5.10.0-8-amd64, x86_64: installed
$ sudo modinfo dahdi_dummy
filename:       /lib/modules/5.10.0-8-amd64/updates/dkms/dahdi_dummy.ko
license:        GPL v2
author:         Robert Pleh <robert.pleh@hermes.si>
description:    Timing-Only Driver
depends:        dahdi
retpoline:      Y
name:           dahdi_dummy
vermagic:       5.10.0-8-amd64 SMP mod_unload modversions 
parm:           debug:int

8.10.6. Applicare una patch al kernel

Alcune funzionalità non sono incluse nel kernel standard perché non mature o per un mancato accordo tra il manutentore del codice sorgente ed i manutentori del kernel. Alcune funzionalità possono essere distribuite come patch che chiunque può applicare liberamente ai sorgenti del kernel.
Debian, talvolta, fornisce alcune di queste patch nei pacchetti linux-patch-*, ma spesso non vengono inserite nei rilasci stabili (a volte per gli stessi motivi per cui non vengono fuse nel kernel ufficiale upstream). Questi pacchetti installano i file nella directory /usr/src/kernel-patches/.
Per applicare una o più di queste patch, usare il comando patch nella directory dei sorgenti e avviare la compilazione del kernel come descritto sopra. Di seguito viene mostrato un vecchio esempio che utilizza linux-patch-grsecurity2 e linux-source-4.9.
$ cd ~/kernel/linux-source-4.9
$ make clean
$ zcat /usr/src/kernel-patches/diffs/grsecurity2/grsecurity-3.1-4.9.11-201702181444.patch.gz | patch -p1
Notare che una patch potrebbe non funzionare con ogni versione del kernel: è possibile che patch fallisca quando la applica ai sorgenti del kernel. Un messaggio d'errore sarà visualizzato e fornirà alcuni dettagli a proposito del fallimento. In questo caso, si deve far riferimento alla documentazione disponibile nel pacchetto Debian della patch (nella directory /usr/share/doc/linux-patch-*/). In molti casi il manutentore indica per quali versioni del kernel è stata realizzata la patch.