
Port di ricerca CVE-2026-98260 Android specifico per il target Xiaomi 17 (pudding)
Catena di exploit Android AArch64 per una build kernel precisa di Xiaomi 17 (nome in codice
pudding): partendo da una normale shell ADB, imposta SELinux in modalità Permissive, azzera UID/GID del processo corrente, completa le Linux capabilities e fornisce un servizio root per il ciclo di avvio corrente.
Questo progetto fa riferimento e porta da CVE-2026-98260-popsicle-android (Xiaomi 17 Pro Max / popsicle), non è una ricerca indipendente implementata da zero.
Una execve() da un thread non principale esegue prima de_thread() per scambiare l'identità del thread. Se l'exec fallisce dopo questo punto (ad esempio exec_mmap() viene interrotta da SIGKILL e restituisce -EINTR), il task esce prima di ripulire i timer POSIX: il k_itimer viene liberato, ma il suo nodo timerqueue rimane nell'albero del task ancora vivo. Quando il processo padre successivamente raccoglie quel task, cleanup_timerqueue() opera di nuovo su questo nodo già liberato, generando un use-after-free.
L'exploit trasforma questo UAF in una scrittura zero limitata di otto byte, quindi procede in tre fasi: SELinux → UID/GID → capabilities complete. Per una spiegazione completa pensata per principianti, vedere docs/VULNERABILITY.md.
| Voce | Valore misurato |
|---|---|
| Dispositivo | Xiaomi 17, modello 25113PN0EC, nome in codice pudding |
| Sistema | Xiaomi HyperOS 4 OS4.0.5.0.XPCCNXM, Android 17 |
| Kernel | 6.12.69-android16-6-g43b5ab7e247d-abogki561813157-4k |
| Dimensione pagina | 4 KiB |
| Punto di partenza | Shell ADB normale autorizzata, UID 2000, SELinux Enforcing, bootloader bloccato |
| Risultato ottenuto | UID/GID 0, SELinux Permissive, CapPrm/CapEff/CapBnd=000001ffffffffff |
| Ciclo di vita | Il servizio root è disponibile per le nuove shell ADB successive nell'ambito di questo avvio; dopo un riavvio è necessario rieseguire |
Verifica indipendente dopo il successo (nuova shell ADB):
uid=0(root) gid=0(root)
CapInh: 000001ffffffffff
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
getenforce: Permissive
Questo non è un root permanente. Non è stato scritto nulla in boot/init_boot o in qualsiasi partizione, il bootloader rimane bloccato; dopo il riavvio SELinux torna a Enforcing e il servizio root scompare.
Nessuna garanzia di successo. Nei test, su 9 avvii è stato completato una sola volta l'intero percorso A→B→C. Le condizioni di superamento delle tre fasi sono indipendenti tra loro:
| Fase | Programma lato dispositivo | Condizione di superamento |
|---|---|---|
| 1. SELinux | exploit-android-perf | getenforce restituisce Permissive, gli altri campi della word di stato restano come previsto |
| 2. Identità | exploit-android-perf-chain | UID/GID dello stesso processo diventano 0, quindi exec fullcap |
| 3. Permessi completi | exploit-android-key-ptr + pc98260_rootd.c | capabilities complete, il servizio root è accessibile da una nuova shell |
Se uno qualsiasi dei passaggi non va a segno viene emesso [PARKED] e lo stato pericoloso viene mantenuto; è necessario riavviare e non si può forzare un nuovo tentativo nello stesso avvio.
--aio 16384 è il valore di tuning di questa macchina (il tentativo riuscito ha centrato la 3903ª pagina di metadati perf).
| Posizione | popsicle | pudding |
|---|---|---|
LINK_SELINUX_STATE | 0xffffffc08289aba0 | 0xffffffc0827f9ba0 |
LINK_GETPID | 0xffffffc080074eac | 0xffffffc080102e10 |
| leak dell'indirizzo del timer | sonda sul valore restituito da alloc_posix_timer | il simbolo è stato inlined, si usa invece l'ingresso $arg1 di posix_cpu_timer_create |
PERF_MAX | 8192 | 16384 (aumenta le probabilità di colpire la pagina) |
Per la motivazione e le prove vedere docs/ADAPTATION.md.
È necessario un Android NDK. La directory bin/ nel repository è compilata con NDK 26.3.11579264 / API 34:
powershell -NoProfile -ExecutionPolicy Bypass -File .\build.ps1 -NdkHome "$env:LOCALAPPDATA\Android\Sdk\ndk\26.3.11579264" -ApiLevel 34
-VerifyReference confronta uno per uno l'SHA-256 dei nuovi artefatti con quelli in bin/; solo usando la stessa toolchain di bin/ si otterrà un'identità byte per byte. Cambiando versione dell'NDK è comunque possibile eseguire, ma gli hash risulteranno diversi.
Artefatti:
| Artefatto | Sorgente di input |
|---|---|
exploit-android-perf | src/exploit-android-perf.c |
exploit-android-perf-chain | src/exploit-android-perf-chain.c |
exploit-android-key-ptr | src/exploit-android-key-ptr.c + src/pc98260_rootd.c |
pc98260-su | src/pc98260_su.c |
La build non si connette al telefono e non scrive sul dispositivo.
Collegare un dispositivo con il debug USB abilitato e già autorizzato, aggiungere platform-tools al PATH:
.\开始98260临时ROOT.bat
o specifica esplicitamente il dispositivo:
powershell -NoProfile -ExecutionPolicy Bypass -File .\run_98260.ps1 -Serial <ADB序列号> -Reboot
Lo script host verifica il modello del dispositivo, la versione incrementale del sistema, la stringa completa del kernel, il boot ID e gli hash dei quattro binari; inoltre imposta /sys/kernel/tracing/tracing_on a 0 prima di avviare ogni fase (in alcune build di HyperOS miuibpf lo mantiene a 1, e la catena di exploit si rifiuterà di funzionare). Quando compare [PARKED], lo script si ferma e suggerisce di riavviare.
In caso di successo, è possibile utilizzare root in questo modo:
adb shell -t /data/local/tmp/pc98260-su
adb shell /data/local/tmp/pc98260-su -c "id"
La catena di exploit richiede il recupero preciso della "pagina in cui si trova il timer di destinazione". Se non si osserva la stessa pagina di destinazione, o se la verifica dopo la scrittura del puntatore risulta incoerente, il programma mantiene gli zombie/mapping correlati e si arresta, evitando un recupero cieco mentre il nodo pendente è ancora referenziato dal kernel. In questo caso, il confine per il tentativo successivo deve essere un nuovo avvio del telefono.
Questo repository non contiene: backup del dispositivo, immagini boot/init_boot, immagini di partizione, payload.bin, kernel/ELF estratti dal firmware, log di esecuzione grezzi, numeri di serie ADB o boot ID. logs/ e build/ sono ignorati da Git. In bin/ sono presenti solo i quattro binari temporanei della catena di privilege escalation.