Skip to content

Freelist corruption

Free edilmiş bir SLUB objesindeki next-pointer'ı overwrite et; böylece bozuk değer per-CPU freelist'e propagate olur ve allocator attacker kontrollü bir adres dağıtır.

Mechanism

SLUB'ın fast allocation path'i per-CPU bir cache kullanır: struct kmem_cache_cpu { void **freelist; unsigned long tid; struct slab *slab; ... }. slab_alloc_node() bunu this_cpu_ptr(s->cpu_slab) ile çeker, bir sonraki free objeyi get_freepointer_safe() ile okur ve freelist'i tid-korumalı bir compare-and-swap altında günceller (tid, preemption/migration boyunca ABA koruması sağlar). Per-CPU freelist boşaldığında slow path __slab_alloc() onu yeniden doldurur.

Note

Corruption hedefi, free bir chunk'ın içinde object + s->offset'te saklanan next-pointer'dır. Allocator o chunk'ı bir sonraki pop ettiğinde, (bozuk) next-pointer kmem_cache_cpu.freelist'e yüklenir. Bu yüzden sonraki allocation attacker'ın değerini döndürür. Tek seferlik bir fake-object yerleştirmesinin aksine, canlı per-CPU freelist'i bozmak sonraki bir dizi allocation'ı yönlendirir; onu genel bir redirection primitive yapan da budur.

Warning

Aynı objeyi yeniden ekleyen naif bir double-free, hardening altında set_freepointer() içindeki BUG_ON(object == fp)'a takılır. Klasik bypass, head-equality check'inin tek bir free'de hiç tetiklenmemesi için bir A -> B -> A chain'i kurar.

Walkthrough

İlgili per-CPU yapısı ve accessor'lar (mm/slub.c):

struct kmem_cache_cpu {
        void            **freelist;  /* next available object */
        unsigned long   tid;         /* globally unique transaction id */
        struct slab     *slab;
};

Kavramsal akış:

  1. Hedef cache'te free bir objenin next-pointer alanını yazmana izin veren bir UAF ya da linear overflow bul.
  2. Onu, allocation'ların döndürmesini istediğin adres olan T ile overwrite et.
  3. Bozuk chunk'ı tüketmek için bir allocate yap; bu, T'yi per-CPU freelist'e yükler.
  4. Tekrar allocate et — SLUB T'yi döndürür. Bunu fake object forgery ile birleştir (T'de bir obje forge et) ya da T'yi doğrudan bozmak için hassas bir yapıya nişanla.

Freelist randomization layout'u bozar: CONFIG_SLAB_FREELIST_RANDOM ile yeni oluşturulan slab'lar objeleri Fisher-Yates ile karıştırılmış bir sırada dağıtır (shuffle_freelist() / s->random_seq), dolayısıyla spray adresleri sıralı olmaz.

Detection

Herhangi bir slab'ın dışına işaret eden bozuk bir free pointer, bir sonraki allocation'da oops üretir; slub_debug=FZP (sanity check'ler, redzone, poison) birçok freelist anomalisini performans pahasına yakalar. KEDR/KASAN build'leri de corruption'ı mümkün kılan altta yatan UAF/overflow'u flag'ler.

Mitigation

CONFIG_SLAB_FREELIST_HARDENED, next-pointer'ı per-cache bir gizli değerle XOR'layarak karıştırır; böylece forge edilmiş bir pointer, s->random leak edilmedikçe garbage'a decode olur. CONFIG_SLAB_FREELIST_RANDOM ise deterministik bitişikliği ortadan kaldırır. Bunlar freelist poisoning altında tartışılan aynı savunmalardır.

References