setxattr spray¶
setxattr()/lsetxattr()'ı kontrollü boyutta bir value buffer ile generic bir kmalloc heap-spray primitive olarak kullan: allocation boyutu value length'ine eşittir ve içerik tamamen attacker-kontrollüdür.
Mechanism¶
xattr write path'i kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN), sonra copy_from_user(kvalue, value, size), sonra kfree(kvalue) yapar. Allocation boyutu tam olarak user'ın sağladığı value length'idir ve byte'lar tam olarak user'ın buffer'ıdır; header overhead'i yoktur.
Note
Value length'ini seçerek allocation'ı belirli bir cache'e (kmalloc-8/16/32/.../n) yönlendirirsin; byte'ları seçerek tüm object'i kontrol edersin. Bu onu, free edilmiş bir slot'u anlık reclaim etmek ya da sonraki allocation için freelist'i şekillendirmek için kullanılabilen generic bir kmalloc spray'i yapar; slab boyutları boyunca ve sendmsg/msgsnd spray'lerinin taşıdığı 16-byte'lık header cezası olmadan.
Walkthrough¶
char val[64]; // value length selects kmalloc-64
char name[32];
memset(val, 0x41, sizeof(val)); // fully controlled contents
for (int i = 0; i < 512; i++) {
snprintf(name, sizeof(name), "user.spray_%d", i); // unique name per call
setxattr("/tmp/spray", name, val, sizeof(val), 0); // each: kmalloc(64)+copy+kfree
}
Beklenen sonuç: 0x41 ile doldurulmuş bellekten 512 geçici (transient) kmalloc-64 allocation'ı; her biri setxattr() onu free etmeden önceki kısa window için free edilmiş bir kmalloc-64 slot'unu reclaim eder.
Warning
Düz setxattr syscall return etmeden önce buffer'ı free eder, dolayısıyla spray transient'tir — free edilmiş bir slot'u anlık reclaim etmek ya da freelist'i tohumlamak için iyidir ama kalıcı değildir. Allocation'ı canlı tutmak için (ör. free edilmiş bir UAF object'in üzerine süresiz bindirmek için) copy_from_user()'ı userfaultfd ya da bir FUSE mapping ile durdur (stall). Alexander Popov'un CVE-2021-26708 exploit'i bu setxattr()+userfaultfd() eşleşmesini bir timing/grooming mekanizması olarak kullanır: asıl açık, AF_VSOCK'taki bir transport-pointer race'idir (4-byte write-after-free, free edilmiş bir virtio_vsock_sock object'inin offset 40'ındaki buf_alloc alanına — bkz. refcount-memory-management-flaw). setxattr()'in copy_from_user()'ı, page-faulting bir region'ın sınırında userfaultfd ile durdurulur; bu, payload'u tam olarak msg_msg.security'yi overwrite etmeden hemen önce durdurmaya yarar (SELinux kontrollerini kırmamak için msg_msg.security kasıtlı olarak korunur).
Mitigation¶
Hardened usercopy, CONFIG_SLAB_FREELIST_RANDOM/HARDENED ve call-site başına slab ayrımı (RANDOM_KMALLOC_CACHES) güvenilirliği azaltır; xattr value-size limitleri hangi cache'lerin erişilebilir olduğunu sınırlar.