Lo sviluppatore del jailbreak di Dopamine discute l’elusivo problema di Spinlock Timeout Panic
Lo strumento di jailbreak Dopamine per dispositivi A12-A15 con iOS e iPadOS 15.0-15.4.1 è l’ultimo jailbreak disponibile per qualsiasi dispositivo più recente di iPhone X in questo momento. Detto questo, non sorprende che oggi sia una scelta popolare tra i jailbreaker.
Ma se hai usato Dopamine o hai seguito il progetto sin dal suo inizio, probabilmente hai sentito una certa parola pronunciata parecchie volte dallo sviluppatore capo del progetto Lars Fröder (@opa334dev) e utenti simili: Spinlock.
In effetti, esiste un problema noto che influisce sul jailbreak di Dopamine chiamato Spinlock Timeout Panic e alla fine il risultato è che il dispositivo dell’utente mostra una schermata rosa e quindi si riavvia in modo apparentemente non provocato. Il problema è stato descritto in termini tecnici come segue:
La mappatura sopra le pagine eseguibili di dyld_shared_cache sembra innescare un comportamento limite nel PPL che a volte causa un timeout sullo spinlock di una pagina di memoria, provocando un panico nel kernel.
Più modifiche vengono installate sulle funzioni hook C e più processi vengono inseriti, più spesso questo comportamento sembra essere attivato.
Sembra che questo problema possa essere risolto cablando tutte le pagine che sono state agganciate, ma lo spazio utente non può sopportare tale blocco e trovare l’oggetto vm_page nella memoria del kernel per invertire direttamente il bit cablato si sta rivelando difficile.
Dal momento che non ho mai riscontrato personalmente uno di questi problemi sul mio dispositivo Dopamine, è stato difficile spiegare come appare o quando accade, ma ho parlato con Fröder per chiedere cosa pensano potrebbe causarlo per saperne di più su come stanno tentando di affrontarlo.
La risposta di Fröder è stata illuminante per le persone non tecniche come me e probabilmente per molti altri nella comunità del jailbreak e da allora è stata pubblicato in una pagina di problema di GitHub affinché il pubblico possa vederlo. La risposta completa, citata di seguito, rivela la comprensione di Fröder del problema Spinlock Timeout Panic:
Ecco un tentativo di spiegazione più approfondita del problema, secondo la mia migliore comprensione attuale. Tieni presente che si basa su presupposti praticamente impossibili da verificare.
Quindi in un sistema multi-thread vengono utilizzati dei “blocchi” per impedire a due thread di interferire tra loro. In questo modo un thread può acquisire un blocco, apportare la modifica e sbloccarlo. Mentre è bloccato, un altro thread che tenta di acquisire il blocco attenderà finché l’oggetto non sarà nuovamente sbloccato.
Uno spinlock è essenzialmente la stessa cosa, usato solo per elementi rilevanti per le prestazioni e la differenza principale è che uno spinlock può scadere se qualcosa impiega troppo tempo il blocco mentre un altro thread sta tentando di acquisire il blocco. Pertanto, quando si acquisisce un blocco e l’oggetto è già bloccato, attenderà alcuni tick e se l’oggetto non viene sbloccato in quell’intervallo di tempo, scadrà.
Questo meccanismo di per sé non è il problema, il problema ha a che fare con le pagine di memoria. Ogni pagina di memoria (che descrive un’area di 16kB di RAM) ha uno spinlock in modo che non ci siano problemi quando più processi tentano di acquisire la stessa pagina contemporaneamente.
Pagine specifiche possono essere mappate in più processi (ad esempio, se entrambi caricano la stessa libreria), riutilizzano la stessa pagina per risparmiare memoria. I tweak vogliono sovrascrivere tale memoria in base al processo, quindi devono prima creare una copia specifica del processo della mappatura esistente e mapparla sopra di essa, in modo che ad esempio una pagina possa essere modificata in un processo rimanendo stock negli altri processi. Il problema sembra verificarsi specificamente durante la mappatura su una pagina che risiede all’interno di dyld_shared_cache.
Il problema ora è che Apple probabilmente non ha mai testato questo tipo di hooking e apparentemente quando lo fai in molti processi, può causare il paging della pagina originale (quella della mappatura condivisa), perché non viene utilizzata attivamente . La paginazione di una pagina la rimuove essenzialmente dalla RAM e quando si accede nuovamente verrà caricata nuovamente. In un sistema azionario ciò non accadrà perché nulla è stato agganciato.
Ora la causa principale sembra essere qualcosa che tenta di reinserire una pagina condivisa/eseguibile precedentemente paginata, questo innesca un problema di prelazione in cui un thread prende lo spinlock e mentre lo ha, viene trasferito in un contesto diverso che prende anche il stesso spinlock (la prelazione è essenzialmente un meccanismo che consente di utilizzare un thread per qualcos’altro anche se è attualmente occupato, il codice deve disabilitarlo e riabilitarlo esplicitamente se c’è un pezzo di codice che dovrebbe essere sempre eseguito in una volta sola) . Quindi sembra esserci un percorso di codice che viene invocato solo da questo particolare comportamento in cui Apple non disabilita correttamente la prelazione, portando un thread a prendere lo stesso spinlock due volte, il che fa scadere il tempo perché il vecchio contesto non è più in esecuzione e non è possibile sbloccare nuovamente lo spinlock.
Per quanto riguarda l’attenuazione, ho provato a modificare le variabili relative allo spinlock per aumentare la soglia necessaria per il timeout, sfortunatamente Apple ci ha fregati perché tutto ciò che è correlato a ciò è protetto da KTRR, per il quale non abbiamo un bypass. Immagino che la soluzione corretta sarebbe quella di “cablare” (cablare una pagina impedisce che venga paginata) ogni pagina da agganciare prima che venga sovrascritta per garantire che la pagina fuori non avvenga mai e quindi il percorso del codice coinvolto nel il problema non si attiva, ho provato un sacco di cose finora ma sembra che sia assolutamente impossibile acquisire un simile cablaggio dallo spazio utente, quindi deve essere fatto all’interno del kernel. Sfortunatamente, le strutture coinvolte in questa specifica mappatura condivisa che causa il problema sono molto contorte e devo ancora trovare un modo per ottenere l’oggetto pagina corretto a cui applicare il cablaggio.
Il problema Spinlock Timeout Panic esiste da quando la dopamina è diventata disponibile per la prima volta e continua a persistere fino ad oggi nonostante molti tentativi di risolvere il problema. Detto questo, aprire il dialogo affinché più persone possano vederlo e a cui contribuiscano è il giusto passo avanti, poiché rende più facile per più menti fare un brainstorming sul problema e su una possibile soluzione.
Fröder spiega la loro prossima idea per tentare di contrastare il problema in un commento successivo:
Quindi il prossimo passo per provare a risolverlo sarebbe trovare la struttura vm_page di una pagina DSC nella memoria del kernel, finora tutti i miei tentativi di trovare una struttura del genere sono falliti.
Anche se non mi ha ancora colpito direttamente, sarà davvero interessante vedere se Fröder sarà in grado di risolvere il problema Spinlock Timeout Panic. Sembra essere più diffuso per gli utenti che installano più modifiche al jailbreak che agganciano le funzioni C. Potrebbe semplicemente essere che il mio dispositivo di prova non abbia molte modifiche installate per attivare il problema, ma so che ci sono molti jailbreaker là fuori che installano tonnellate di modifiche al jailbreak, più di quanto farei mai.
Vedi anche: Come eseguire il jailbreak dei dispositivi A12-A15 con iOS e iPadOS 15.0-15.4.1 con Dopamine
Sei mai stato colpito da uno Spinlock Timeout Panic descritto come una schermata rosa prima di un riavvio improvviso durante l’utilizzo del jailbreak di Dopamine? Fatecelo sapere nella sezione commenti in basso.