
Un'implementazione Go di PinTheft (CVE-2026-43494)
Porting in Go di pintheft - LPE double-free di RDS zcopy. Membro della classe di vulnerabilità Dirty Frag.
[!IMPORTANT] Arch Linux è una delle distribuzioni più esposte a questa vulnerabilità, essendo tra le poche in cui il modulo RDS può essere tipicamente caricato di default.
Il bug è in rds_message_zcopy_from_user(). La funzione esegue il pin GUP delle pagine utente una alla volta tramite FOLL_GET. Se una pagina successiva va in fault (ad es. una pagina guardia PROT_NONE), il percorso di errore chiama put_page() sulle pagine già sottoposte a pin, poi rds_message_purge() chiama di nuovo __free_page() su di esse perché op_mmp_znotifier è stato posto a NULL ma op_nents/voci sg sono rimaste intatte. Quando la pagina ha ancora altri riferimenti, __free_page decrementa silenziosamente il refcount. Ogni sendmsg fallito ruba esattamente un riferimento dalla prima pagina.
CONFIG_INIT_ON_ALLOC_DEFAULT_ONEsegue il pin della pagina target tramite io_uring REGISTER_BUFFERS, che aggiunge GUP_PIN_COUNTING_BIAS (1024) al refcount attraverso FOLL_PIN. Ruba tutti i 1024 riferimenti di pin con invii zcopy falliti. Il refcount della pagina è ora ~1 (solo il mapping PTE). munmap segue il normale percorso di __folio_put, che chiama mem_cgroup_uncharge (azzerando memcg_data) prima di liberare. Nessun controllo bad_page scatta.
io_uring mantiene il struct page* grezzo nel proprio array bvec senza controlli di liveness. Dopo che la pagina viene riutilizzata come page cache per un binario suid, IORING_OP_READ_FIXED scrive il nostro payload al suo interno tramite quel puntatore dangling.
IORING_REGISTER_CLONE_BUFFERS incrementa imu->refs. Un figlio demone generato da fork mantiene aperto il fd del clone ring - io_buffer_unmap vede refs > 1 e salta unpin_user_folio, prevenendo la corruzione del refcount sulla pagina liberata.
Esegui il pin sulla CPU 0, svuota le voci PCP obsolete prima di liberare - la nostra pagina finisce in cima quando l'allocatore della page cache la preleva.
REGISTER_BUFFERS(+1024) -> CLONE_BUFFERS(imu->refs=2) ->
daemon holds clone -> steal 1024 refs -> evict page cache ->
drain PCP -> munmap(free) -> pread(reclaim) ->
READ_FIXED(overwrite) -> verify -> exec -> root
go build -o pintheft-go .
./pintheft-go
In caso di successo apre una shell di root tramite PTY. Il binario su disco non viene toccato.
sudo cp /tmp/.backup_pintheft_<pid> /usr/bin/su && sudo chmod u+s /usr/bin/su
CONFIG_RDS=m, CONFIG_RDS_TCP=m (caricati automaticamente via SO_RDS_TRANSPORT=2)CONFIG_IO_URING=y con io_uring_disabled=0tra l'altro adoro Arch Linux :)