Skip to content

SLAB freelist randomization

Per-slab freelist'i karıştırır, böylece yeni allocate edilen kernel object'leri artık sıralı adres sırasında geri gelmez ve heap-layout determinizmini zayıflatır.

Mechanism

Note

Kavramsal: NEDEN çalışır, invariant/teori.

Kernel SLAB/SLUB allocator'ı, bitişik bir backing page'i (bir "slab") sabit-boyutlu object slot'larına böler ve free slot'lar boyunca singly-linked bir freelist geçirir. Varsayılan olarak, yeni bir slab oluşturulduğunda freelist artan index sırasında inşa edilir: ilk allocation slot 0'ı döner, sonraki slot 1'i, vb. Bu determinizm, tam olarak heap exploitation'ın dayandığı şeydir — bir attacker heap'i öyle groom eder ki bir victim object kontrol ettiği bir object'e bitişik düşer (veya onun içine reclaim edilir), çünkü bir sonraki kmalloc()'un hangi slot'u vereceğini tahmin edebilir.

CONFIG_SLAB_FREELIST_RANDOM o invariant'ı kırar. Slab initialization'da freelist sırası bir Fisher-Yates shuffle ile permüte edilir, böylece slot'ların verilme sırası artık memory'deki sıralarıyla eşleşmez. Dizi her allocation'da yeniden üretilmez (bu entropy'yi tüketir ve çok pahalıya mal olur); bunun yerine cache boyutu başına bir kez önceden hesaplanmış bir random dizi üretilir ve yeni oluşturulan her slab page o template'e random bir başlangıç kayması seçer. Her kmem_cache boot'ta erkenden seed edilen (early-boot entropy kıtlığını ele almak için mümkün olduğunda RDRAND kullanarak) kendi randomize listesini taşır.

Koruma probabilistik ve tasarım gereği kısmidir. Yazarın belirttiği gibi, "cannot mitigate heap overflows" — bir linear overflow hâlâ source object'in fiziksel olarak ardından geleni bozar. Kaldırdığı şey control'dür: attacker artık belirli bir yüksek-değerli object'in fiziksel komşu olmasını güvenilir şekilde ayarlayamaz ve overflow-to-use-after-free chaining çok daha az güvenilir hale gelir.

Walkthrough

Çalışan kernel'in bu option ile build edilip edilmediğini kontrol edin:

$ grep -E 'SLAB_FREELIST_(RANDOM|HARDENED)' /boot/config-$(uname -r)
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_SLAB_FREELIST_RANDOM=y

/boot/config-* yoksa, CONFIG_IKCONFIG_PROC=y olduğunda aynı semboller /proc/config.gz altında yaşar:

$ zcat /proc/config.gz | grep SLAB_FREELIST_RANDOM
CONFIG_SLAB_FREELIST_RANDOM=y

Etkinin kavramsal gösterimi — aynı boyuttan birkaç object'i arka arkaya allocate edip adreslerini inceleyin. Randomization olmadan, dönen pointer'lar taze bir slab içinde kesinlikle sıralıdır:

/* illustrative: kernel module fragment */
void *a = kmalloc(256, GFP_KERNEL);
void *b = kmalloc(256, GFP_KERNEL);
void *c = kmalloc(256, GFP_KERNEL);
pr_info("a=%px b=%px c=%px\n", a, b, c);

Beklenen davranış:

  • CONFIG_SLAB_FREELIST_RANDOM olmadan: bir taze slab içinde üç pointer tam olarak object stride'ı kadar artar (a, a+256, a+512).
  • Onunla: üç pointer aynı slab page içinde, ama karıştırılmış, sıralı olmayan bir düzende düşer — b, daha sonra allocate edilmiş olsa bile memory'de a'dan önce gelebilir.

Warning

Bu, bir grooming-hardening özelliğidir, bir bounds check değil. Heap feng-shui'sinin maliyetini ve güvenilmezliğini artırır, ama bir object'in sonunu aşan bir write'ı durdurmaz. Katmanlı koruma için onu CONFIG_SLAB_FREELIST_HARDENED (freelist-pointer obfuscation, bkz. slab-freelist-hardening) ve init-on-free ile eşleştirin.

Mitigation

Build zamanında enable edin:

CONFIG_SLAB_FREELIST_RANDOM=y

v4.7–v4.8 döneminde tanıtıldı: ilk SLAB implementasyonu Linux 4.7'de geldi ve SLUB uzantısı 4.8'de izledi. Option varsayılan olarak disabled'dır. Ölçülen overhead küçüktür (yazarın testlerinde SLUB'da ~%3 mertebesinde, en kötü durum sürekli yeni page'lerin oluşturulduğu size class'larında); genellikle production hardening için yeterince ucuz kabul edilir.

References