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:
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_RANDOMolmadan: 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'dea'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:
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.