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
Unsurprisingly, Debian manages the kernel in the form of a package, which is not how kernels have traditionally been compiled and installed. Since the kernel remains under the control of the packaging system, it can then be removed cleanly, or deployed on several machines. Furthermore, the scripts associated with these packages automate the interaction with the bootloader and the initrd generator.
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.
We assume the linux-source-5.10 package has been installed. It contains /usr/src/linux-source-6.1.tar.xz
, a compressed archive of the kernel sources. You must extract these files in a new directory (not directly under /usr/src/
, since there is no need for special permissions to compile a Linux kernel): ~/kernel/
is appropriate.
$
mkdir ~/kernel; cd ~/kernel
$
tar -xaf /usr/src/linux-source-6.1.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.
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-6.1.0-21-amd64 ~/kernel/linux-source-6.1/.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 (3.0.10-8+deb12u1) ...
Setting up linux-compiler-gcc-12-x86 (6.1.99-1) ...
Setting up fxload (0.0.20081013-2) ...
Setting up linux-headers-6.1.0-23-common (6.1.99-1) ...
Setting up linux-kbuild-6.1 (6.1.99-1) ...
Setting up dahdi-dkms (1:2.11.1.0.20170917~dfsg-8.4) ...
Loading new dahdi-2.11.1.0.20170917 DKMS files...
Building for 6.1.0-23-amd64
Building initial module for 6.1.0-23-amd64
Done.
dahdi_dummy.ko:
Running module version sanity check.
- Original module
- No original module exists within this kernel
- Installation
- Installing to /lib/modules/6.1.0-23-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/6.1.0-23-amd64/updates/dkms/
[..]
depmod...
Setting up dahdi-linux (1:2.11.1.0.20170917~dfsg-8.4) ...
Setting up linux-headers-6.1.0-23-amd64 (6.1.99-1) ...
/etc/kernel/header_postinst.d/dkms:
dkms: running auto installation service for kernel 6.1.0-23-amd64.
dkms: autoinstall for kernel: 6.1.0-23-amd64.
Setting up linux-headers-amd64 (6.1.99-1) ...
Processing triggers for man-db (2.11.2-2) ...
$
sudo dkms status
dahdi/2.11.1.0.20170917, 6.1.0-23-amd64, x86_64: installed
$
sudo modinfo dahdi_dummy
filename: /lib/modules/6.1.0-23-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: 6.1.0-23-amd64 SMP preempt mod_unload modversions
sig_id: PKCS#7
signer: DKMS module signing key
sig_key: 69:A6:CA:D5:86:6A:FE:F4:A8:04:6A:31:8B:AB:E1:07:88:BA:45:C7
sig_hashalgo: sha256
signature: 9B:F9:8E:38:4D:06:A6:20:52:33:D9:AE:9D:B9:83:17:BB:5A:18:F1:
F2:5B:F3:12:06:0A:1D:48:C3:BA:89:2C:40:64:1C:2C:52:7C:46:BE:
27:49:F5:55:42:1B:71:38:A2:1B:FA:58:BB:CE:7C:70:2C:EC:37:7B:
65:91:A1:E7:23:6E:B6:92:9D:B9:20:43:F5:39:7F:95:CA:36:DC:C0:
DA:82:49:AC:21:69:65:DF:5D:0F:C5:8F:E5:E6:92:76:F1:DD:18:7E:
91:D2:DC:43:86:CA:5B:66:7C:FF:AE:EA:F9:06:F8:55:4A:1F:C0:56:
8B:F7:6C:9E:77:35:9B:E0:14:9D:C4:68:D8:5E:FD:3F:53:73:F1:B6:
12:67:9E:F4:68:48:C8:A7:80:69:42:01:83:52:D8:EF:54:FE:11:E4:
63:3C:6F:B3:B6:BF:E9:4F:DF:52:C4:A7:6B:35:D6:3B:C9:E2:FD:48:
70:41:D1:D1:68:4C:D4:12:7F:CB:7D:92:E5:E6:79:4A:5B:5E:7C:38:
1D:98:B2:EF:0E:F3:8D:07:1B:51:75:2A:58:2E:F2:53:BA:6A:79:F5:
AD:D1:12:08:E1:15:EC:5C:7A:CF:99:A2:9B:DB:BB:C0:EE:BD:C0:96:
77:92:D7:CC:68:14:A2:61:E0:F2:65:64:54:70:B8:73
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.