Quando il kernel che cerchi non esiste

Avevo un vecchio Galaxy Note9 fermo in un cassetto.

Non era rotto, non era particolarmente malandato. Semplicemente, a un certo punto aveva smesso di essere il telefono che usavo tutti i giorni. Uno di quei dispositivi che continui a conservare perché "prima o poi potrebbe servire".

E così ho pensato che, invece di lasciarlo lì, potevo dargli un nuovo scopo.

L'idea era abbastanza semplice: installarci Kali NetHunter e usarlo come dispositivo dedicato per fare pratica con alcuni strumenti di cybersecurity, ovviamente in ambienti controllati.

Il progetto, sulla carta, sembrava anche abbastanza interessante.

Il problema è che la carta, come spesso accade, non raccontava tutta la storia.

Prima di tutto, LineageOS

Il primo passo era abbastanza obbligato: portare il Note9 a LineageOS 20.

Non tanto perché volessi cambiare sistema operativo per il gusto di farlo, ma perché volevo costruire sopra una base abbastanza pulita e soprattutto compatibile con il lavoro che avrei dovuto fare dopo.

Il primo tentativo, naturalmente, non è andato liscio.

Lo ZIP di LineageOS che avevo scaricato non era integro. Il risultato è stato un bel bootloop e qualche minuto passato a chiedermi cosa avessi combinato.

La risposta, alla fine, era molto meno interessante di quanto sperassi.

Il file era semplicemente corrotto.

Il checksum avrebbe dovuto dirmelo subito.

E infatti me l'ha detto. Solo che l'ho controllato dopo.

Una delle classiche lezioni che continuiamo a imparare anche dopo averle già imparate altre volte: controllare sempre il checksum prima di flashare qualcosa.

Risolto quello, LineageOS è partito e il telefono è tornato perfettamente utilizzabile.

A quel punto potevo cominciare la parte interessante.

O almeno così pensavo.

Costruire un kernel da zero

NetHunter richiede alcune modifiche al kernel per poter esporre determinate funzionalità.

Quindi il passo successivo era procurarsi i sorgenti e costruire un kernel adatto al Note9.

La prima cosa che ho trovato su GitHub sembrava promettente.

Fork del kernel, modifiche già orientate a NetHunter, documentazione, commit vari.

Perfetto.

Solo che c'era un piccolo particolare.

Quel kernel era stato preparato per una versione di Android completamente diversa da quella che stavo usando.

In altre parole, avevo trovato qualcosa che sembrava esattamente quello che cercavo, ma non lo era.

E qui è iniziata una delle parti più lunghe del lavoro: trovare il sorgente giusto.

Non un sorgente che "sembra compatibile".

Non un sorgente relativo allo stesso telefono.

Quello che corrisponde davvero al kernel che stava girando sul mio Note9.

Perché con un kernel non basta guardare il nome del dispositivo e dire "è quello".

Versione Android, versione del kernel, configurazione, codice sorgente e build effettivamente installata devono combaciare.

E più andavo avanti, più diventava evidente che quel dettaglio sarebbe stato importante.

Il primo bootloop

A un certo punto avevo qualcosa.

Il kernel compilava.

Nessun errore.

Il file risultante era pronto per essere flashato.

Quindi l'ho flashato.

Il Note9 si è riavviato.

Logo Samsung.

Aspetto.

Ancora logo Samsung.

Aspetto un altro po'.

Niente.

Bootloop.

La cosa positiva è che, prima di iniziare tutta questa storia, avevo fatto un backup.

E questa è probabilmente la parte più noiosa da raccontare, ma anche quella che vale più di tutte le altre:

fate il backup prima di flashare qualcosa di sperimentale.

Non "quando qualcosa va storto".

Prima.

Grazie al backup ho potuto tornare indietro senza trasformare un esperimento su un vecchio telefono in un pomeriggio dedicato al recupero di un vecchio telefono.

Il dispositivo era salvo.

Il problema, però, rimaneva.

Comincia la caccia al colpevole

Quando un kernel non parte, le possibilità sono abbastanza numerose.

E la cosa più facile da fare è iniziare a cambiare dieci cose contemporaneamente.

È anche il modo migliore per non capire mai cosa abbia risolto il problema.

Ho quindi provato a procedere per esclusione.

La prima ipotesi era la più ovvia: magari era il codice NetHunter che avevo aggiunto.

Quindi ho tolto quello che avevo modificato e ho provato a costruire una versione il più possibile vicina al kernel originale.

Stesso risultato.

Bootloop.

A quel punto il sospettato successivo è diventato il toolchain.

E qui è saltata fuori una cosa interessante.

La versione di Clang che stavo utilizzando non era quella giusta: c'era una differenza di due major version rispetto a quella prevista per quella specifica build.

Cambio toolchain.

Ricompilo.

Flash.

Stesso schermo. Stesso punto morto.

Bene.

Almeno un'altra ipotesi eliminata.

Poi sono arrivati i residui di codice più vecchio, alcune parti legacy, le configurazioni e infine il DTB.

Ogni volta cercavo di cambiare una cosa sola.

Ogni volta ricompilavo.

Ogni volta flashavo.

E ogni volta il telefono faceva esattamente la stessa cosa.

Logo Samsung.

Bootloop.

A quel punto iniziava a diventare difficile sostenere che fosse semplicemente "un piccolo errore da qualche parte".

Il muro

La svolta, in realtà, è arrivata confrontando due cose che avrei dovuto confrontare molto prima.

Da una parte c'era la configurazione del kernel che era effettivamente in esecuzione sul telefono.

Dall'altra quella utilizzata per compilare il mio kernel.

Sembravano simili.

Ma non erano la stessa cosa.

E soprattutto, andando più a fondo, mancavano interi pezzi di codice.

Non qualche configurazione dimenticata.

Non una voce sbagliata nel file di configurazione.

Mancava proprio il codice sorgente necessario.

A quel punto la situazione diventava abbastanza frustrante.

Perché fino a quel momento avevo ragionato come se il problema fosse:

"Sto usando il codice giusto, ma sto sbagliando qualcosa nella compilazione."

Invece la domanda era diventata:

"E se il codice che sto usando non fosse quello che è stato usato per costruire il kernel che gira davvero sul telefono?"

E purtroppo era proprio questa la direzione in cui portavano gli indizi.

Il sorgente pubblico che avevo trovato non combaciava con quello che serviva per riprodurre esattamente il kernel presente sul dispositivo.

Non era più una questione di trovare la configurazione corretta.

Mancava la materia prima.

Ancora un paio di tentativi, perché mollare subito non mi piace

Prima di arrendermi, però, ho voluto controllare ancora qualche pista.

Ho trovato alcuni fork alternativi del kernel e li ho confrontati con quello che avevo. Poi ho seguito anche un suggerimento trovato nella community, che riguardava l'utilizzo di Magisk con un approccio leggermente diverso per ottenere alcune delle funzionalità che cercavo.

Li ho provati con calma, cercando di capire cosa stavo effettivamente facendo e senza limitarmi a copiare una sequenza di comandi trovata in un post del 2021.

Niente. O meglio: niente che risolvesse il problema fondamentale.

Continuavo a tornare allo stesso punto: le fonti disponibili non corrispondevano al kernel reale del telefono. Ed era un'informazione molto più importante di qualsiasi errore di compilazione.

A un certo punto bisogna smettere

Questa è stata probabilmente la parte più difficile dell'intero progetto.

Non tecnicamente.

Mentalmente.

Perché quando hai passato parecchie ore a cercare di far funzionare qualcosa, l'istinto è pensare che basti ancora un tentativo.

Un'altra configurazione.

Un'altra versione di Clang.

Un altro fork.

Un'altra patch.

Un'altra sera.

Ma a un certo punto bisogna distinguere tra:

"non ho ancora trovato la soluzione"

e

"la soluzione che sto cercando probabilmente non è disponibile."

Nel mio caso ero arrivato alla seconda situazione.

Non avevo un sorgente pubblico che corrispondesse realmente al kernel installato sul dispositivo.

E senza quello, potevo continuare a fare tentativi, ma sarebbero diventati sempre più simili a una lotteria.

Quindi ho deciso di fermarmi.

Per l'obiettivo originale, ha più senso utilizzare un altro dispositivo con supporto NetHunter già disponibile e mantenuto, invece di continuare a combattere con un kernel per il quale non ho il sorgente corretto.

Il Note9, comunque, non è finito nel cassetto.

È rimasto con LineageOS, funziona perfettamente e, anzi, adesso è probabilmente un telefono di scorta migliore di prima.

Non è stato tempo perso

Alla fine non ho ottenuto quello che volevo.

Non ho un Note9 con NetHunter.

Però ho ottenuto qualcosa di altrettanto utile: ho capito perché non ce l'ho.

E non è la stessa cosa.

Ho imparato qualcosa sulla compatibilità tra kernel e sorgenti, ho verificato il toolchain, ho fatto pratica con la compilazione, ho imparato ancora una volta quanto sia importante fare backup e controllare i checksum.

E soprattutto mi sono portato a casa una lezione che vale anche fuori dai kernel Android.

Ci sono problemi che richiedono semplicemente più tempo.

E poi ci sono problemi per i quali continuare a lavorare non significa necessariamente avvicinarsi alla soluzione.

A volte stai cercando un file.

Una versione.

Un pezzo di codice.

Qualcosa che non è disponibile.

E in quel caso puoi passare altre dieci ore a cercarlo, ma non diventerà magicamente disponibile alla decima ora.

Il Note9 è quindi rimasto lì, con il suo LineageOS e pronto a fare il telefono di scorta quando servirà.

NetHunter, invece, finirà su un altro dispositivo.

Non è esattamente come avevo immaginato di concludere il progetto.

Ma, considerando il punto da cui ero partito, direi che non è andata poi così male.

← Torna a tutti i post