anon_vma_name spray¶
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ...)kullanarak attacker'ın kontrol ettiğistruct anon_vma_nameobjelerini küçük kmalloc cache'lerinde allocate et; bir heap-spray / reclaim primitive olarak kullan.
Mechanism¶
Note
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, name), kernel'in userspace'ten
gelen bir VMA adını tutmak için bir struct anon_vma_name allocate etmesini sağlar.
Adın uzunluğu attacker tarafından kontrol edilir ve obje normal kmalloc cache'lerinden
GFP_KERNEL ile allocate edilir; bu da seçilen bir boyuttaki freed slot'u doldurabilen,
esnek, cross-cache gerektirmeyen bir spray/reclaim primitive verir. Reuse invariant'ı:
kernel ada göre deduplicate eder, dolayısıyla her spray girdisi farklı bir ad
kullanmalı; aksi halde yeni bir obje allocate edilmek yerine mevcut anon_vma_name
objesi yeniden kullanılır.
Obje ve allocation noktası:
struct anon_vma_name {
struct kref kref; /* 4-byte refcount header */
char name[]; /* flexible array, attacker-sized */
};
anon_name = kmalloc(struct_size(anon_name, name, count), GFP_KERNEL);
4-byte'lık bir header ve >4 ile 80 byte arası bir ad ile allocation'lar kabaca kmalloc-16'dan kmalloc-96'ya kadar yayılır (4-byte header + en az 5-byte ad = min. 9 byte, SLUB'da kmalloc-16'ya yuvarlanır).
Walkthrough¶
Sprayed objeleri allocate et ve free et:
int rename_vma(unsigned long addr, unsigned long size, char *name) {
return prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, name);
}
/* spray: each call MUST use a unique name string */
for (int i = 0; i < N; i++) {
snprintf(buf, sizeof(buf), "spray-%d-%s", i, payload);
rename_vma(map_addr, 0x1000, buf);
}
/* free a sprayed object (refcount -> 0) */
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_addr, 0x1000, NULL);
Ad, show_map_vma() tarafından /proc/<pid>/maps içine "[anon_shmem:%s]" olarak
yazdırılır; dolayısıyla maps'i okumak, name field'ını dolduran byte'ları açığa çıkarır — bir
leak channel'ı, ancak yazdırma ilk NUL byte'ında durur:
Warning
CONFIG_ANON_VMA_NAME gerektirir (yaygın distro'larda aktif; Linux 6.1.37'de doğrulandı).
/proc/<pid>/maps'teki NUL-truncation, read channel olarak kullanımını sınırlar — en
değerli yanı, kontrol edilen boyutta bir fill/reclaim objesi olmasıdır.
Mitigation¶
Ad leak'i ilk NUL byte'ında kesilir ve okunabilir pencereyi sınırlar. Userspace tarafından kontrol edilen boyuttaki allocation'ları ayrı bucket'lara izole eden hardening (kmem_buckets tarzı ayrım), spray'in aynı cache içindeki target objelere karşı güvenilirliğini azaltır.