Skip to content

Slab grooming

Kontrollü alloc/free aracılığıyla SLUB slab ve page-allocator layout'unu deterministik olarak düzenle; böylece bir victim object attacker-kontrollü bir object'e komşu düşer ya da onun slot'unu yeniden kullanır.

Mechanism

SLUB belirli bir boyuttaki object'leri slab'lardan (bir veya birden fazla bitişik page) dağıtır. Bir slab içindeki allocation sırası büyük ölçüde deterministiktir (per-CPU freelist'ten LIFO) ve bir cache tükendiğinde SLUB buddy/page allocator'dan taze bir slab ister. Bu kuralları anlayan bir attacker heap'i önceden şekillendirebilir; böylece sonraki allocation tam istenen yere düşer.

Note

Grooming, SLUB ile page allocator arasındaki etkileşimi exploit eder. (1) hedef kmalloc-N cache'ini partial-slab boşluğunu tüketmek için önceden doldurarak, sonra (2) page-allocator freelist'lerini aynı order'daki allocation'larla boşaltarak, attacker taze bir slab'ın bilinen bir page'den carve edilmesini zorlar; bu da sonraki victim/attacker object'lerinin yerleşimini deterministik yapar — overflow'lar için komşuluk ya da UAF reclaim için kesin slot yeniden kullanımı.

Walkthrough

Kanonik deterministik dizi (Project Zero'nun CVE-2017-7308 packet-socket exploit'inden; burada packet_sock ≈1920 B kmalloc-2048'e yuvarlanır ve groom için kullanılan AF_PACKET ring-buffer blokları 0x8000 boyutundadır):

  1. Cache'i doldur: kmalloc-2048'deki partial-slab boşluğunu tüketmek için ~512 packet_sock object'i allocate et.
  2. Page allocator'ı boşalt: page allocator'ın ilgili freelist'leri boşalsın ve öngörülebilir olsun diye ~1024 0x8000 ring-buffer bloğu allocate et.
  3. Kontrollü bloğu yerleştir: exploit'in 0x8000 ring-buffer bloğunu allocate et — artık komşu yerleşim garantili.
  4. Victim'leri yerleştir: victim packet_sock struct'larını, overflow hedefinin hemen ardına düşecek şekilde allocate et.
// Sketch: exhaust kmalloc-2048, then allocate adjacent 0x8000 blocks via packet rings.
for (i = 0; i < 512;  i++)  s[i]  = socket(AF_PACKET, SOCK_RAW, 0);   // packet_sock
for (i = 0; i < 1024; i++)  drain_ring_block(0x8000);                  // drain page alloc
alloc_controlled_ring_block(0x8000);                                   // adjacent block
for (i = 0; i < N;    i++)  v[i]  = socket(AF_PACKET, SOCK_RAW, 0);    // victims after target

Beklenen sonuç: victim'e güvenilir biçimde komşu olan (ya da onun tarafından yeniden kullanılan) kontrollü bir allocation; böylece bir OOB write ya da UAF reclaim rastgele bellek yerine seçilen bir hedefi vurur.

Mitigation

CONFIG_SLAB_FREELIST_RANDOM slab-içi sırayı bozar; RANDOM_KMALLOC_CACHES / SLAB_BUCKETS allocation site'larını ayırır; page-allocator freelist randomization'ı (CONFIG_SHUFFLE_PAGE_ALLOCATOR) cross-cache komşuluk determinizmini azaltır — hepsi grooming güvenilirliğini düşürür ama ortadan kaldırmaz.

References