
Albero sorgente del kernel Linux 4.1.15 con focus su CVE-2022-42703, una vulnerabilità use-after-free nel sottosistema netfilter, per analisi e ricerca di sfruttamento.
Rilascio del kernel Linux 4.x http://kernel.org/
Queste sono le note di rilascio per la versione 4 del kernel Linux. Leggetele attentamente, poiché spiegano di cosa si tratta, come installare il kernel e cosa fare se qualcosa va storto.
COS'È LINUX?
Linux è un clone del sistema operativo Unix, scritto da zero da Linus Torvalds con l'aiuto di un team eterogeneo di hacker sparsi per la Rete. Mira alla conformità con POSIX e la Specifica UNIX Singola.
Ha tutte le funzionalità che ci si aspetterebbe da un Unix moderno e completo, inclusi vero multitasking, memoria virtuale, librerie condivise, caricamento su richiesta, eseguibili con copy-on-write condiviso, corretta gestione della memoria e networking multistack, inclusi IPv4 e IPv6.
È distribuito sotto la Licenza Pubblica Generale GNU - vedere il file COPYING allegato per maggiori dettagli.
SU QUALI HARDWARE FUNZIONA?
Sebbene originariamente sviluppato per PC basati su x86 a 32 bit (386 o superiore), oggi Linux funziona anche (almeno) sulle architetture Compaq Alpha AXP, Sun SPARC e UltraSPARC, Motorola 68000, PowerPC, PowerPC64, ARM, Hitachi SuperH, Cell, IBM S/390, MIPS, HP PA-RISC, Intel IA-64, DEC VAX, AMD x86-64, AXIS CRIS, Xtensa, Tilera TILE, AVR32 e Renesas M32R.
Linux è facilmente portabile sulla maggior parte delle architetture generiche a 32 o 64 bit purché dispongano di una unità di gestione della memoria impaginata (PMMU) e di un porting del compilatore GNU C (gcc) (parte della Collezione di Compilatori GNU, GCC). Linux è stato anche portato su diverse architetture senza PMMU, sebbene la funzionalità sia ovviamente alquanto limitata. Linux è stato anche portato su se stesso. Ora è possibile eseguire il kernel come applicazione in spazio utente - questo si chiama UserMode Linux (UML).
DOCUMENTAZIONE:
Esiste molta documentazione disponibile sia in formato elettronico su Internet che in libri, sia specifica per Linux che relativa a domande generali su UNIX. Raccomando di consultare le sottodirectory di documentazione su qualsiasi sito FTP Linux per i libri LDP (Progetto di Documentazione Linux). Questo README non vuole essere documentazione sul sistema: ci sono fonti molto migliori.
Ci sono vari file README nella sottodirectory Documentation/: questi contengono tipicamente note di installazione specifiche del kernel per alcuni driver, per esempio. Vedere Documentation/00-INDEX per un elenco di ciò che è contenuto in ogni file. Si prega di leggere il file Changes, poiché contiene informazioni sui problemi che possono derivare dall'aggiornamento del kernel.
La sottodirectory Documentation/DocBook/ contiene diverse guide per sviluppatori e utenti del kernel. Queste guide possono essere rese in vari formati: PostScript (.ps), PDF, HTML e pagine man, tra gli altri. Dopo l'installazione, "make psdocs", "make pdfdocs", "make htmldocs", o "make mandocs" renderanno la documentazione nel formato richiesto.
INSTALLAZIONE DEL SORGENTE DEL KERNEL:
Se installate i sorgenti completi, mettete il tarball del kernel in una directory dove avete i permessi (ad es. la vostra home directory) e decomprimetelo:
xz -cd linux-4.X.tar.xz | tar xvf -
Sostituite "X" con il numero di versione dell'ultimo kernel.
NON utilizzate l'area /usr/src/linux! Quest'area contiene un set (di solito incompleto) di header del kernel che vengono usati dai file di header delle librerie. Dovrebbero corrispondere alla libreria e non essere alterati da qualunque sia il kernel del giorno.
Potete anche aggiornare tra i rilasci 4.x tramite patch. Le patch sono distribuite in formato xz. Per installare tramite patch, ottenete tutti i file di patch più recenti, entrate nella directory principale del sorgente del kernel (linux-4.X) ed eseguite:
xz -cd ../patch-4.x.xz | patch -p1
Sostituite "x" con tutte le versioni maggiori della versione "X" del vostro albero dei sorgenti corrente, in_ordine, e dovreste essere a posto. Potreste voler rimuovere i file di backup (qualche-nome-file~ o qualche-nome-file.orig), e assicurarvi che non ci siano patch fallite (qualche-nome-file# o qualche-nome-file.rej). Se ce ne sono, io o voi abbiamo commesso un errore.
A differenza delle patch per i kernel 4.x, le patch per i kernel 4.x.y (note anche come kernel -stable) non sono incrementali ma si applicano direttamente al kernel base 4.x. Ad esempio, se il vostro kernel base è 4.0 e volete applicare la patch 4.0.3, non dovete applicare prima le patch 4.0.1 e 4.0.2. Allo stesso modo, se state eseguendo la versione del kernel 4.0.2 e volete passare alla 4.0.3, dovete invertire prima la patch 4.0.2 (cioè, patch -R) prima di applicare la patch 4.0.3. Potete leggere di più su questo in Documentation/applying-patches.txt
In alternativa, lo script patch-kernel può essere usato per automatizzare questo processo. Determina la versione corrente del kernel e applica qualsiasi patch trovata.
linux/scripts/patch-kernel linux
Il primo argomento nel comando sopra è la posizione del sorgente del kernel. Le patch vengono applicate dalla directory corrente, ma una directory alternativa può essere specificata come secondo argomento.
Assicuratevi di non avere file .o obsoleti e dipendenze in giro:
cd linux make mrproper
Ora dovreste avere i sorgenti installati correttamente.
REQUISITI SOFTWARE
Compilare ed eseguire i kernel 4.x richiede versioni aggiornate di vari pacchetti software. Consultate Documentation/Changes per i numeri di versione minima richiesti e come ottenere aggiornamenti per questi pacchetti. Attenzione: usare versioni eccessivamente vecchie di questi pacchetti può causare errori indiretti molto difficili da rintracciare, quindi non date per scontato di poter semplicemente aggiornare i pacchetti quando sorgono problemi evidenti durante la compilazione o il funzionamento.
DIRECTORY DI BUILD PER IL KERNEL:
Quando si compila il kernel, tutti i file di output saranno per default memorizzati insieme al codice sorgente del kernel. Usando l'opzione "make O=dir/output" potete specificare una posizione alternativa per i file di output (incluso .config). Esempio:
codice sorgente del kernel: /usr/src/linux-4.X
directory di build: /home/nome/build/kernel
Per configurare e compilare il kernel, usate:
cd /usr/src/linux-4.X
make O=/home/nome/build/kernel menuconfig
make O=/home/nome/build/kernel
sudo make O=/home/nome/build/kernel modules_install install
Nota bene: Se viene usata l'opzione 'O=dir/output', allora deve essere usata per tutte le invocazioni di make.
CONFIGURAZIONE DEL KERNEL:
Non saltate questo passaggio anche se state solo aggiornando una versione minore. Nuove opzioni di configurazione vengono aggiunte in ogni rilascio, e problemi strani si presenteranno se i file di configurazione non sono impostati come previsto. Se volete trasferire la vostra configurazione esistente a una nuova versione con il minimo lavoro, usate "make oldconfig", che vi chiederà solo le risposte alle nuove domande.
Comandi di configurazione alternativi sono:
"make config" Interfaccia di testo semplice.
"make menuconfig" Menu colorati basati su testo, elenchi radio e dialoghi.
"make nconfig" Menu colorati basati su testo migliorati.
"make xconfig" Strumento di configurazione basato su X windows (Qt).
"make gconfig" Strumento di configurazione basato su X windows (Gtk).
"make oldconfig" Imposta come predefinite tutte le domande basate sul contenuto del vostro file ./.config esistente e chiede informazioni sui nuovi simboli di configurazione.
"make silentoldconfig" Come sopra, ma evita di ingombrare lo schermo con domande già risposte. Aggiorna inoltre le dipendenze.
"make olddefconfig" Come sopra, ma imposta i nuovi simboli ai loro valori predefiniti senza chiedere.
"make defconfig" Crea un file ./.config usando i valori predefiniti dei simboli da arch/$ARCH/defconfig o arch/$ARCH/configs/${PLATFORM}_defconfig, a seconda dell'architettura.
"make ${PLATFORM}_defconfig" Crea un file ./.config usando i valori predefiniti dei simboli da arch/$ARCH/configs/${PLATFORM}_defconfig. Usa "make help" per ottenere un elenco di tutte le piattaforme disponibili per la vostra architettura.
"make allyesconfig" Crea un file ./.config impostando i valori dei simboli a 'y' il più possibile.
"make allmodconfig" Crea un file ./.config impostando i valori dei simboli a 'm' il più possibile.
"make allnoconfig" Crea un file ./.config impostando i valori dei simboli a 'n' il più possibile.
"make randconfig" Crea un file ./.config impostando i valori dei simboli a valori casuali.
"make localmodconfig" Crea una configurazione basata sulla configurazione corrente e sui moduli caricati (lsmod). Disabilita qualsiasi opzione di modulo non necessaria per i moduli caricati.
Per creare una localmodconfig per un'altra macchina,
salvate l'lsmod di quella macchina in un file
e passatelo come parametro LSMOD.
target$ lsmod > /tmp/mylsmod
target$ scp /tmp/mylsmod host:/tmp
host$ make LSMOD=/tmp/mylsmod localmodconfig
Quanto sopra funziona anche durante la cross-compilazione.
"make localyesconfig" Simile a localmodconfig, tranne che convertirà tutte le opzioni dei moduli in opzioni integrate (=y).
Potete trovare maggiori informazioni sull'uso degli strumenti di configurazione del kernel Linux in Documentation/kbuild/kconfig.txt.
NOTE su "make config":
Avere driver non necessari renderà il kernel più grande, e può in alcune circostanze portare a problemi: il probing per una scheda controller inesistente può confondere gli altri controller.
Compilare il kernel con "Tipo di processore" impostato a un valore superiore a 386 darà come risultato un kernel che NON funziona su un 386. Il kernel lo rileverà all'avvio e si fermerà.
Un kernel con emulazione matematica compilata userà comunque il coprocessore se presente: l'emulazione matematica non verrà mai utilizzata in quel caso. Il kernel sarà leggermente più grande, ma funzionerà su macchine diverse indipendentemente dal fatto che abbiano o meno un coprocessore matematico.
I dettagli di configurazione "kernel hacking" di solito risultano in un kernel più grande o più lento (o entrambi), e possono persino rendere il kernel meno stabile configurando alcune routine per tentare attivamente di rompere il codice errato per trovare problemi del kernel (kmalloc()). Pertanto dovreste probabilmente rispondere 'n' alle domande per funzionalità di "sviluppo", "sperimentali" o "debug".
COMPILAZIONE DEL KERNEL:
Assicuratevi di avere almeno gcc 3.2 disponibile. Per maggiori informazioni, fate riferimento a Documentation/Changes.
Notate che potete ancora eseguire programmi utente a.out con questo kernel.
Eseguite un "make" per creare un'immagine del kernel compressa. È anche possibile fare "make install" se avete lilo installato per adattarsi ai makefile del kernel, ma potreste voler controllare prima la vostra configurazione specifica di lilo.
Per eseguire l'installazione effettiva, dovete essere root, ma nessuna delle normali operazioni di build dovrebbe richiederlo. Non prendete il nome di root invano.
Se avete configurato alcune parti del kernel come `modules', dovrete anche eseguire "make modules_install".
Output verboso della compilazione/build del kernel:
Normalmente, il sistema di build del kernel funziona in una modalità abbastanza silenziosa (ma non totalmente). Tuttavia, a volte voi o altri sviluppatori del kernel avete bisogno di vedere i comandi di compilazione, link o altri esattamente come vengono eseguiti. Per questo, usate la modalità di build "verbose". Questo si fa inserendo "V=1" nel comando "make". Ad es.:
make V=1 all
Per fare in modo che il sistema di build dica anche la ragione della ricompilazione di ogni target, usate "V=2". Il valore predefinito è "V=0".
Tenete un kernel di backup a portata di mano nel caso qualcosa vada storto. Questo è vero specialmente per i rilasci di sviluppo, poiché ogni nuovo rilascio contiene nuovo codice che non è stato ancora sottoposto a debug. Assicuratevi di tenere anche un backup dei moduli corrispondenti a quel kernel. Se state installando un nuovo kernel con lo stesso numero di versione del vostro kernel funzionante, fate un backup della directory dei moduli prima di eseguire "make modules_install".
In alternativa, prima di compilare, usate l'opzione di configurazione del kernel "LOCALVERSION" per aggiungere un suffisso unico alla versione regolare del kernel. LOCALVERSION può essere impostato nel menu "Impostazioni Generali".
Per avviare il vostro nuovo kernel, dovrete copiare l'immagine del kernel (ad es. .../linux/arch/i386/boot/bzImage dopo la compilazione) nel posto dove si trova il vostro kernel avviabile regolare.
Non è più supportato l'avvio di un kernel direttamente da un floppy senza l'assistenza di un bootloader come LILO.
Se avviate Linux dal disco rigido, probabilmente usate LILO, che usa l'immagine del kernel specificata nel file /etc/lilo.conf. Il file immagine del kernel è di solito /vmlinuz, /boot/vmlinuz, /bzImage o /boot/bzImage. Per usare il nuovo kernel, salvate una copia della vecchia immagine e copiate la nuova immagine sopra la vecchia. Poi, DOVETE RIESEGUIRE LILO per aggiornare la mappa di caricamento!! Se non lo fate, non sarete in grado di avviare la nuova immagine del kernel.
Reinstallare LILO di solito è questione di eseguire /sbin/lilo. Potreste voler modificare /etc/lilo.conf per specificare una voce per la vostra vecchia immagine del kernel (ad esempio, /vmlinux.old) nel caso in cui quella nuova non funzioni. Consultate la documentazione di LILO per maggiori informazioni.
Dopo aver reinstallato LILO, dovreste essere a posto. Spegnete il sistema, riavviate e godetevi!
Se mai doveste aver bisogno di cambiare il dispositivo root predefinito, la modalità video, la dimensione del ramdisk, ecc. nell'immagine del kernel, usate il programma 'rdev' (o, in alternativa, le opzioni di avvio di LILO quando appropriato). Non c'è bisogno di ricompilare il kernel per cambiare questi parametri.
Riavviate con il nuovo kernel e godetevelo.
SE QUALCOSA VA STORTO:
Se avete problemi che sembrano essere dovuti a bug del kernel, controllate il file MAINTAINERS per vedere se c'è una persona specifica associata con la parte del kernel con cui avete problemi. Se non c'è nessuno elencato lì, allora la seconda opzione migliore è inviare una mail a me ([email protected]) e possibilmente a qualsiasi altra mailing-list pertinente o al newsgroup.
In tutte le segnalazioni di bug, per favore dite di quale kernel state parlando, come riprodurre il problema e qual è la vostra configurazione (usate il buon senso). Se il problema è nuovo, ditemelo; se il problema è vecchio, cercate di dirmi quando lo avete notato per la prima volta.
Se il bug produce un messaggio come
unable to handle kernel paging request at address C0000010 Oops: 0002 EIP: 0010:XXXXXXXX eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx ds: xxxx es: xxxx fs: xxxx gs: xxxx Pid: xx, process nr: xx xx xx xx xx xx xx xx xx xx xx
o informazioni di debug del kernel simili sul vostro schermo o nel vostro log di sistema, per favore duplicatelo esattamente. Il dump può sembrare incomprensibile a voi, ma contiene informazioni che possono aiutare il debug del problema. Il testo sopra il dump è anche importante: dice qualcosa sul perché il kernel ha dumpato il codice (nell'esempio sopra, è dovuto a un puntatore del kernel non valido). Maggiori informazioni su come interpretare il dump si trovano in Documentation/oops-tracing.txt
Se avete compilato il kernel con CONFIG_KALLSYMS potete inviare il dump così com'è; altrimenti dovrete usare il programma "ksymoops" per dare un senso al dump (ma compilare con CONFIG_KALLSYMS è di solito preferibile). Questa utility può essere scaricata da ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops/ . In alternativa, potete eseguire la ricerca del dump a mano:
Nei dump di debug come quello sopra, aiuta enormemente se potete cercare cosa significa il valore EIP. Il valore esadecimale in sé non aiuta molto me o chiunque altro: dipenderà dalla vostra particolare configurazione del kernel. Quello che dovreste fare è prendere il valore esadecimale dalla riga EIP (ignorate "0010:"), e cercarlo nella lista dei nomi del kernel per vedere quale funzione del kernel contiene l'indirizzo incriminato.
Per trovare il nome della funzione del kernel, dovrete trovare il binario di sistema associato al kernel che ha mostrato il sintomo. Questo è il file 'linux/vmlinux'. Per estrarre la lista dei nomi e confrontarla con l'EIP del crash del kernel, eseguite:
nm vmlinux | sort | less
Questo vi darà un elenco di indirizzi del kernel ordinati in ordine crescente, dal quale è semplice trovare la funzione che contiene l'indirizzo incriminato. Notate che l'indirizzo fornito dai messaggi di debug del kernel non corrisponderà necessariamente esattamente con gli indirizzi delle funzioni (anzi, è molto improbabile), quindi non potete semplicemente fare un 'grep' dell'elenco: l'elenco, tuttavia, vi darà il punto di partenza di ogni funzione del kernel, quindi cercando la funzione che ha un indirizzo di partenza inferiore a quello che state cercando ma che è seguita da una funzione con un indirizzo più alto, troverete quella che volete. In effetti, potrebbe essere una buona idea includere un po' di "contesto" nella vostra segnalazione di problema, dando qualche riga attorno a quella interessante.
Se per qualche motivo non potete fare quanto sopra (avete un'immagine precompilata del kernel o simile), fornire quante più informazioni possibili sulla vostra configurazione aiuterà. Per favore leggete il documento REPORTING-BUGS per dettagli.
In alternativa, potete usare gdb su un kernel in esecuzione. (sola lettura; cioè non potete cambiare valori o impostare punti di interruzione.) Per fare questo, prima compilate il kernel con -g; modificate arch/i386/Makefile in modo appropriato, poi eseguite un "make clean". Dovrete anche abilitare CONFIG_PROC_FS (tramite "make config").
Dopo aver riavviato con il nuovo kernel, eseguite "gdb vmlinux /proc/kcore". Ora potete usare tutti i soliti comandi gdb. Il comando per cercare il punto dove il vostro sistema è crashato è "l *0xXXXXXXXX". (Sostituite i XXX con il valore EIP.)
gdb su un kernel non in esecuzione attualmente fallisce perché gdb (erroneamente) ignora l'offset di partenza per il quale il kernel è compilato.